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" 54dd5e3fbcSChuck Lever #include "trace.h" 555e1533c7SStanislav Kinsbursky 561da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 571da177e4SLinus Torvalds 58f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 59f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 60f32f3c2dSJ. Bruce Fields .si_generation = ~0, 61f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 62f32f3c2dSJ. Bruce Fields }; 63f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 64f32f3c2dSJ. Bruce Fields /* all fields zero */ 65f32f3c2dSJ. Bruce Fields }; 6619ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 6719ff0f28STigran Mkrtchyan .si_generation = 1, 6819ff0f28STigran Mkrtchyan }; 69fb500a7cSTrond Myklebust static const stateid_t close_stateid = { 70fb500a7cSTrond Myklebust .si_generation = 0xffffffffU, 71fb500a7cSTrond Myklebust }; 72f32f3c2dSJ. Bruce Fields 73ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 74fd39ca9aSNeilBrown 75f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 76f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 7719ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 78ae254dacSAndrew Elble #define CLOSE_STATEID(stateid) (!memcmp((stateid), &close_stateid, sizeof(stateid_t))) 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /* forward declarations */ 81f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 826011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 83362063a5SScott Mayhew void nfsd4_end_grace(struct nfsd_net *nn); 84624322f1SOlga Kornievskaia static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); 851da177e4SLinus Torvalds 868b671b80SJ. Bruce Fields /* Locking: */ 878b671b80SJ. Bruce Fields 888b671b80SJ. Bruce Fields /* 898b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 908b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 918b671b80SJ. Bruce Fields * eventually cover more: 928b671b80SJ. Bruce Fields */ 93cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 948b671b80SJ. Bruce Fields 954f34bd05SAndrew Elble enum nfsd4_st_mutex_lock_subclass { 964f34bd05SAndrew Elble OPEN_STATEID_MUTEX = 0, 974f34bd05SAndrew Elble LOCK_STATEID_MUTEX = 1, 984f34bd05SAndrew Elble }; 994f34bd05SAndrew Elble 100b401be22SJeff Layton /* 101b401be22SJeff Layton * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for 102b401be22SJeff Layton * the refcount on the open stateid to drop. 103b401be22SJeff Layton */ 104b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq); 105b401be22SJeff Layton 10689c905beSJ. Bruce Fields /* 10789c905beSJ. Bruce Fields * A waitqueue where a writer to clients/#/ctl destroying a client can 10889c905beSJ. Bruce Fields * wait for cl_rpc_users to drop to 0 and then for the client to be 10989c905beSJ. Bruce Fields * unhashed. 11089c905beSJ. Bruce Fields */ 11189c905beSJ. Bruce Fields static DECLARE_WAIT_QUEUE_HEAD(expiry_wq); 11289c905beSJ. Bruce Fields 1139258a2d5SJeff Layton static struct kmem_cache *client_slab; 114abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 115abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 116abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 117abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 118abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 1198287f009SSachin Bhamare static struct kmem_cache *odstate_slab; 120e60d4398SNeilBrown 12166b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 122508dc6e1SBenny Halevy 123c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; 12476d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; 1250162ac2bSChristoph Hellwig 12666b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 127508dc6e1SBenny Halevy { 12866b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 12966b2b9b2SJ. Bruce Fields } 13066b2b9b2SJ. Bruce Fields 131f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 132f0f51f5cSJ. Bruce Fields { 133f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 13466b2b9b2SJ. Bruce Fields return nfserr_jukebox; 13566b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 13666b2b9b2SJ. Bruce Fields return nfs_ok; 13766b2b9b2SJ. Bruce Fields } 13866b2b9b2SJ. Bruce Fields 139221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 140221a6876SJ. Bruce Fields { 141221a6876SJ. Bruce Fields return clp->cl_time == 0; 142221a6876SJ. Bruce Fields } 143221a6876SJ. Bruce Fields 144221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 145221a6876SJ. Bruce Fields { 1460a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1470a880a28STrond Myklebust 1480a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1490a880a28STrond Myklebust 150221a6876SJ. Bruce Fields if (is_client_expired(clp)) 151221a6876SJ. Bruce Fields return nfserr_expired; 15214ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 153221a6876SJ. Bruce Fields return nfs_ok; 154221a6876SJ. Bruce Fields } 155221a6876SJ. Bruce Fields 156221a6876SJ. Bruce Fields /* must be called under the client_lock */ 157221a6876SJ. Bruce Fields static inline void 158221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 159221a6876SJ. Bruce Fields { 160221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 161221a6876SJ. Bruce Fields 162221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 163221a6876SJ. Bruce Fields WARN_ON(1); 164221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 165221a6876SJ. Bruce Fields __func__, 166221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 167221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 168221a6876SJ. Bruce Fields return; 169221a6876SJ. Bruce Fields } 170221a6876SJ. Bruce Fields 171221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 17220b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 173221a6876SJ. Bruce Fields } 174221a6876SJ. Bruce Fields 175ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 176221a6876SJ. Bruce Fields { 1770a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1780a880a28STrond Myklebust 1790a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1800a880a28STrond Myklebust 18114ed14ccSJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_rpc_users)) 182221a6876SJ. Bruce Fields return; 183221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 184221a6876SJ. Bruce Fields renew_client_locked(clp); 18589c905beSJ. Bruce Fields else 18689c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 187221a6876SJ. Bruce Fields } 188221a6876SJ. Bruce Fields 1894b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 1904b24ca7dSJeff Layton { 1914b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1924b24ca7dSJeff Layton 19314ed14ccSJ. Bruce Fields if (!atomic_dec_and_lock(&clp->cl_rpc_users, &nn->client_lock)) 194d6c249b4SJeff Layton return; 195d6c249b4SJeff Layton if (!is_client_expired(clp)) 196d6c249b4SJeff Layton renew_client_locked(clp); 19789c905beSJ. Bruce Fields else 19889c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 1994b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 2004b24ca7dSJeff Layton } 2014b24ca7dSJeff Layton 202d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 203d4e19e70STrond Myklebust { 204d4e19e70STrond Myklebust __be32 status; 205d4e19e70STrond Myklebust 206d4e19e70STrond Myklebust if (is_session_dead(ses)) 207d4e19e70STrond Myklebust return nfserr_badsession; 208d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 209d4e19e70STrond Myklebust if (status) 210d4e19e70STrond Myklebust return status; 211d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 212d4e19e70STrond Myklebust return nfs_ok; 213d4e19e70STrond Myklebust } 214d4e19e70STrond Myklebust 215d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 216d4e19e70STrond Myklebust { 217d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 2180a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2190a880a28STrond Myklebust 2200a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 221d4e19e70STrond Myklebust 222d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 223d4e19e70STrond Myklebust free_session(ses); 224d4e19e70STrond Myklebust put_client_renew_locked(clp); 225d4e19e70STrond Myklebust } 226d4e19e70STrond Myklebust 227d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 228d4e19e70STrond Myklebust { 229d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 230d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 231d4e19e70STrond Myklebust 232d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 233d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 234d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 235d4e19e70STrond Myklebust } 236d4e19e70STrond Myklebust 23776d348faSJeff Layton static struct nfsd4_blocked_lock * 23876d348faSJeff Layton find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 23976d348faSJeff Layton struct nfsd_net *nn) 24076d348faSJeff Layton { 24176d348faSJeff Layton struct nfsd4_blocked_lock *cur, *found = NULL; 24276d348faSJeff Layton 2430cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 24476d348faSJeff Layton list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { 24576d348faSJeff Layton if (fh_match(fh, &cur->nbl_fh)) { 24676d348faSJeff Layton list_del_init(&cur->nbl_list); 2477919d0a2SJeff Layton list_del_init(&cur->nbl_lru); 24876d348faSJeff Layton found = cur; 24976d348faSJeff Layton break; 25076d348faSJeff Layton } 25176d348faSJeff Layton } 2520cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 25376d348faSJeff Layton if (found) 254cb03f94fSNeilBrown locks_delete_block(&found->nbl_lock); 25576d348faSJeff Layton return found; 25676d348faSJeff Layton } 25776d348faSJeff Layton 25876d348faSJeff Layton static struct nfsd4_blocked_lock * 25976d348faSJeff Layton find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 26076d348faSJeff Layton struct nfsd_net *nn) 26176d348faSJeff Layton { 26276d348faSJeff Layton struct nfsd4_blocked_lock *nbl; 26376d348faSJeff Layton 26476d348faSJeff Layton nbl = find_blocked_lock(lo, fh, nn); 26576d348faSJeff Layton if (!nbl) { 26676d348faSJeff Layton nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); 26776d348faSJeff Layton if (nbl) { 268e1e8399eSVasily Averin INIT_LIST_HEAD(&nbl->nbl_list); 269e1e8399eSVasily Averin INIT_LIST_HEAD(&nbl->nbl_lru); 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 497a451b123STrond Myklebust if (!f) 498a451b123STrond Myklebust return NULL; 499de18643dSTrond Myklebust spin_lock(&f->fi_lock); 500de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 501de18643dSTrond Myklebust if (!ret) { 502de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 503de18643dSTrond Myklebust if (!ret) 504de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 505de18643dSTrond Myklebust } 506de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 507de18643dSTrond Myklebust return ret; 508de18643dSTrond Myklebust } 509de18643dSTrond Myklebust 51002a3508dSTrond Myklebust static atomic_long_t num_delegations; 511697ce9beSZhang Yanfei unsigned long max_delegations; 512ef0f3390SNeilBrown 513ef0f3390SNeilBrown /* 514ef0f3390SNeilBrown * Open owner state (share locks) 515ef0f3390SNeilBrown */ 516ef0f3390SNeilBrown 51716bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 51816bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 51916bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 52016bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 521ef0f3390SNeilBrown 522d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 523ddc04c41SJ. Bruce Fields { 524ddc04c41SJ. Bruce Fields unsigned int ret; 525ddc04c41SJ. Bruce Fields 526ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 52716bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 528ddc04c41SJ. Bruce Fields } 529ef0f3390SNeilBrown 530ef0f3390SNeilBrown /* hash table for nfs4_file */ 531ef0f3390SNeilBrown #define FILE_HASH_BITS 8 532ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 53335079582SShan Wei 534ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) 535ddc04c41SJ. Bruce Fields { 536ca943217STrond Myklebust return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); 537ca943217STrond Myklebust } 538ca943217STrond Myklebust 539ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh) 540ca943217STrond Myklebust { 541ca943217STrond Myklebust return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); 542ca943217STrond Myklebust } 543ca943217STrond Myklebust 54489876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 545ef0f3390SNeilBrown 54612659651SJeff Layton static void 54712659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 5483477565eSJ. Bruce Fields { 5497214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5507214e860SJeff Layton 55112659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 55212659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 55312659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 55412659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 5553477565eSJ. Bruce Fields } 5563477565eSJ. Bruce Fields 55712659651SJeff Layton static __be32 55812659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 559998db52cSJ. Bruce Fields { 5607214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5617214e860SJeff Layton 56212659651SJeff Layton /* Does this access mode make sense? */ 56312659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 56412659651SJeff Layton return nfserr_inval; 56512659651SJeff Layton 566baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 567baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 568baeb4ff0SJeff Layton return nfserr_share_denied; 569baeb4ff0SJeff Layton 57012659651SJeff Layton __nfs4_file_get_access(fp, access); 57112659651SJeff Layton return nfs_ok; 572998db52cSJ. Bruce Fields } 573998db52cSJ. Bruce Fields 574baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 575baeb4ff0SJeff Layton { 576baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 577baeb4ff0SJeff Layton if (deny) { 578baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 579baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 580baeb4ff0SJeff Layton return nfserr_inval; 581baeb4ff0SJeff Layton 582baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 583baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 584baeb4ff0SJeff Layton return nfserr_share_denied; 585baeb4ff0SJeff Layton 586baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 587baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 588baeb4ff0SJeff Layton return nfserr_share_denied; 589baeb4ff0SJeff Layton } 590baeb4ff0SJeff Layton return nfs_ok; 591baeb4ff0SJeff Layton } 592baeb4ff0SJeff Layton 593998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 594f9d7562fSJ. Bruce Fields { 595de18643dSTrond Myklebust might_lock(&fp->fi_lock); 596de18643dSTrond Myklebust 597de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 598fd4f83fdSJeff Layton struct nfsd_file *f1 = NULL; 599fd4f83fdSJeff Layton struct nfsd_file *f2 = NULL; 600de18643dSTrond Myklebust 6016d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 6020c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 6036d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 604de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 605de18643dSTrond Myklebust if (f1) 606fd4f83fdSJeff Layton nfsd_file_put(f1); 607de18643dSTrond Myklebust if (f2) 608fd4f83fdSJeff Layton nfsd_file_put(f2); 609f9d7562fSJ. Bruce Fields } 610f9d7562fSJ. Bruce Fields } 611f9d7562fSJ. Bruce Fields 61212659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 613998db52cSJ. Bruce Fields { 61412659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 61512659651SJeff Layton 61612659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 617998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 61812659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 61912659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 620998db52cSJ. Bruce Fields } 621998db52cSJ. Bruce Fields 6228287f009SSachin Bhamare /* 6238287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 6248287f009SSachin Bhamare * pNFS for proper return on close semantics. 6258287f009SSachin Bhamare * 6268287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 6278287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 6288287f009SSachin Bhamare */ 6298287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6308287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 6318287f009SSachin Bhamare { 6328287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6338287f009SSachin Bhamare 6348287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 6358287f009SSachin Bhamare if (co) { 6368287f009SSachin Bhamare co->co_client = clp; 637cff7cb2eSElena Reshetova refcount_set(&co->co_odcount, 1); 6388287f009SSachin Bhamare } 6398287f009SSachin Bhamare return co; 6408287f009SSachin Bhamare } 6418287f009SSachin Bhamare 6428287f009SSachin Bhamare static void 6438287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 6448287f009SSachin Bhamare { 6458287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 6468287f009SSachin Bhamare 6478287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 6488287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 6498287f009SSachin Bhamare } 6508287f009SSachin Bhamare 6518287f009SSachin Bhamare static inline void 6528287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 6538287f009SSachin Bhamare { 6548287f009SSachin Bhamare if (co) 655cff7cb2eSElena Reshetova refcount_inc(&co->co_odcount); 6568287f009SSachin Bhamare } 6578287f009SSachin Bhamare 6588287f009SSachin Bhamare static void 6598287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 6608287f009SSachin Bhamare { 6618287f009SSachin Bhamare struct nfs4_file *fp; 6628287f009SSachin Bhamare 6638287f009SSachin Bhamare if (!co) 6648287f009SSachin Bhamare return; 6658287f009SSachin Bhamare 6668287f009SSachin Bhamare fp = co->co_file; 667cff7cb2eSElena Reshetova if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 6688287f009SSachin Bhamare list_del(&co->co_perfile); 6698287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 6708287f009SSachin Bhamare 6718287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 6728287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 6738287f009SSachin Bhamare } 6748287f009SSachin Bhamare } 6758287f009SSachin Bhamare 6768287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6778287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 6788287f009SSachin Bhamare { 6798287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6808287f009SSachin Bhamare struct nfs4_client *cl; 6818287f009SSachin Bhamare 6828287f009SSachin Bhamare if (!new) 6838287f009SSachin Bhamare return NULL; 6848287f009SSachin Bhamare 6858287f009SSachin Bhamare cl = new->co_client; 6868287f009SSachin Bhamare 6878287f009SSachin Bhamare spin_lock(&fp->fi_lock); 6888287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 6898287f009SSachin Bhamare if (co->co_client == cl) { 6908287f009SSachin Bhamare get_clnt_odstate(co); 6918287f009SSachin Bhamare goto out; 6928287f009SSachin Bhamare } 6938287f009SSachin Bhamare } 6948287f009SSachin Bhamare co = new; 6958287f009SSachin Bhamare co->co_file = fp; 6968287f009SSachin Bhamare hash_clnt_odstate_locked(new); 6978287f009SSachin Bhamare out: 6988287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 6998287f009SSachin Bhamare return co; 7008287f009SSachin Bhamare } 7018287f009SSachin Bhamare 702d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 703d19fb70dSKinglong Mee void (*sc_free)(struct nfs4_stid *)) 704996e0938SJ. Bruce Fields { 7053abdb607SJ. Bruce Fields struct nfs4_stid *stid; 7063abdb607SJ. Bruce Fields int new_id; 7073abdb607SJ. Bruce Fields 708f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 7093abdb607SJ. Bruce Fields if (!stid) 7103abdb607SJ. Bruce Fields return NULL; 711996e0938SJ. Bruce Fields 7124770d722SJeff Layton idr_preload(GFP_KERNEL); 7134770d722SJeff Layton spin_lock(&cl->cl_lock); 71478599c42SJ. Bruce Fields /* Reserving 0 for start of file in nfsdfs "states" file: */ 71578599c42SJ. Bruce Fields new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 1, 0, GFP_NOWAIT); 7164770d722SJeff Layton spin_unlock(&cl->cl_lock); 7174770d722SJeff Layton idr_preload_end(); 718ebd6c707STejun Heo if (new_id < 0) 7193abdb607SJ. Bruce Fields goto out_free; 720d19fb70dSKinglong Mee 721d19fb70dSKinglong Mee stid->sc_free = sc_free; 7223abdb607SJ. Bruce Fields stid->sc_client = cl; 7233abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 7243abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 7253abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 726a15dfcd5SElena Reshetova refcount_set(&stid->sc_count, 1); 7279767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 728624322f1SOlga Kornievskaia INIT_LIST_HEAD(&stid->sc_cp_list); 7293abdb607SJ. Bruce Fields 730996e0938SJ. Bruce Fields /* 7313abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 7323abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 7333abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 7343abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 7353abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 7363abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 7373abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 738996e0938SJ. Bruce Fields */ 7393abdb607SJ. Bruce Fields return stid; 7403abdb607SJ. Bruce Fields out_free: 7412c44a234SWei Yongjun kmem_cache_free(slab, stid); 7423abdb607SJ. Bruce Fields return NULL; 7432a74aba7SJ. Bruce Fields } 7442a74aba7SJ. Bruce Fields 745e0639dc5SOlga Kornievskaia /* 746e0639dc5SOlga Kornievskaia * Create a unique stateid_t to represent each COPY. 747e0639dc5SOlga Kornievskaia */ 748624322f1SOlga Kornievskaia static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, 749624322f1SOlga Kornievskaia unsigned char sc_type) 750e0639dc5SOlga Kornievskaia { 751e0639dc5SOlga Kornievskaia int new_id; 752e0639dc5SOlga Kornievskaia 7539cc76801SArnd Bergmann stid->stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; 754624322f1SOlga Kornievskaia stid->stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; 755624322f1SOlga Kornievskaia stid->sc_type = sc_type; 756624322f1SOlga Kornievskaia 757e0639dc5SOlga Kornievskaia idr_preload(GFP_KERNEL); 758e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 759624322f1SOlga Kornievskaia new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT); 760624322f1SOlga Kornievskaia stid->stid.si_opaque.so_id = new_id; 761e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 762e0639dc5SOlga Kornievskaia idr_preload_end(); 763e0639dc5SOlga Kornievskaia if (new_id < 0) 764e0639dc5SOlga Kornievskaia return 0; 765e0639dc5SOlga Kornievskaia return 1; 766e0639dc5SOlga Kornievskaia } 767e0639dc5SOlga Kornievskaia 768624322f1SOlga Kornievskaia int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy) 769624322f1SOlga Kornievskaia { 770624322f1SOlga Kornievskaia return nfs4_init_cp_state(nn, ©->cp_stateid, NFS4_COPY_STID); 771624322f1SOlga Kornievskaia } 772624322f1SOlga Kornievskaia 773624322f1SOlga Kornievskaia struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, 774624322f1SOlga Kornievskaia struct nfs4_stid *p_stid) 775624322f1SOlga Kornievskaia { 776624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 777624322f1SOlga Kornievskaia 778624322f1SOlga Kornievskaia cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL); 779624322f1SOlga Kornievskaia if (!cps) 780624322f1SOlga Kornievskaia return NULL; 78120b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 782624322f1SOlga Kornievskaia refcount_set(&cps->cp_stateid.sc_count, 1); 783624322f1SOlga Kornievskaia if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID)) 784624322f1SOlga Kornievskaia goto out_free; 785624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 786624322f1SOlga Kornievskaia list_add(&cps->cp_list, &p_stid->sc_cp_list); 787624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 788624322f1SOlga Kornievskaia return cps; 789624322f1SOlga Kornievskaia out_free: 790624322f1SOlga Kornievskaia kfree(cps); 791624322f1SOlga Kornievskaia return NULL; 792624322f1SOlga Kornievskaia } 793624322f1SOlga Kornievskaia 794624322f1SOlga Kornievskaia void nfs4_free_copy_state(struct nfsd4_copy *copy) 795e0639dc5SOlga Kornievskaia { 796e0639dc5SOlga Kornievskaia struct nfsd_net *nn; 797e0639dc5SOlga Kornievskaia 798624322f1SOlga Kornievskaia WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID); 799e0639dc5SOlga Kornievskaia nn = net_generic(copy->cp_clp->net, nfsd_net_id); 800e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 801624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 802624322f1SOlga Kornievskaia copy->cp_stateid.stid.si_opaque.so_id); 803624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 804624322f1SOlga Kornievskaia } 805624322f1SOlga Kornievskaia 806624322f1SOlga Kornievskaia static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid) 807624322f1SOlga Kornievskaia { 808624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 809624322f1SOlga Kornievskaia struct nfsd_net *nn; 810624322f1SOlga Kornievskaia 811624322f1SOlga Kornievskaia nn = net_generic(net, nfsd_net_id); 812624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 813624322f1SOlga Kornievskaia while (!list_empty(&stid->sc_cp_list)) { 814624322f1SOlga Kornievskaia cps = list_first_entry(&stid->sc_cp_list, 815624322f1SOlga Kornievskaia struct nfs4_cpntf_state, cp_list); 816624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 817624322f1SOlga Kornievskaia } 818e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 819e0639dc5SOlga Kornievskaia } 820e0639dc5SOlga Kornievskaia 821b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 8224cdc951bSJ. Bruce Fields { 8236011695dSTrond Myklebust struct nfs4_stid *stid; 8246011695dSTrond Myklebust 825d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 8266011695dSTrond Myklebust if (!stid) 8276011695dSTrond Myklebust return NULL; 8286011695dSTrond Myklebust 829d19fb70dSKinglong Mee return openlockstateid(stid); 8306011695dSTrond Myklebust } 8316011695dSTrond Myklebust 8326011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 8336011695dSTrond Myklebust { 8346011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 8356011695dSTrond Myklebust atomic_long_dec(&num_delegations); 8364cdc951bSJ. Bruce Fields } 8374cdc951bSJ. Bruce Fields 8386282cd56SNeilBrown /* 8396282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 8406282cd56SNeilBrown * out again straight away. 8416282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 8426282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 8436282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 8446282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 8456282cd56SNeilBrown * filter. 8466282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 8476282cd56SNeilBrown * unless both are empty of course. 8486282cd56SNeilBrown * 8496282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 8506282cd56SNeilBrown * low 3 bytes as hash-table indices. 8516282cd56SNeilBrown * 852f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 8536282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 8546282cd56SNeilBrown * except when swapping the two filters. 8556282cd56SNeilBrown */ 856f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 8576282cd56SNeilBrown static struct bloom_pair { 8586282cd56SNeilBrown int entries, old_entries; 859b3f255efSArnd Bergmann time64_t swap_time; 8606282cd56SNeilBrown int new; /* index into 'set' */ 8616282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 8626282cd56SNeilBrown } blocked_delegations; 8636282cd56SNeilBrown 8646282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 8656282cd56SNeilBrown { 8666282cd56SNeilBrown u32 hash; 8676282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 8686282cd56SNeilBrown 8696282cd56SNeilBrown if (bd->entries == 0) 8706282cd56SNeilBrown return 0; 871b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 872f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 873b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 8746282cd56SNeilBrown bd->entries -= bd->old_entries; 8756282cd56SNeilBrown bd->old_entries = bd->entries; 8766282cd56SNeilBrown memset(bd->set[bd->new], 0, 8776282cd56SNeilBrown sizeof(bd->set[0])); 8786282cd56SNeilBrown bd->new = 1-bd->new; 879b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 8806282cd56SNeilBrown } 881f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 8826282cd56SNeilBrown } 88387545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 8846282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 8856282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 8866282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 8876282cd56SNeilBrown return 1; 8886282cd56SNeilBrown 8896282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 8906282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 8916282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 8926282cd56SNeilBrown return 1; 8936282cd56SNeilBrown 8946282cd56SNeilBrown return 0; 8956282cd56SNeilBrown } 8966282cd56SNeilBrown 8976282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 8986282cd56SNeilBrown { 8996282cd56SNeilBrown u32 hash; 9006282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 9016282cd56SNeilBrown 90287545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 9036282cd56SNeilBrown 904f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 9056282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 9066282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 9076282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 9086282cd56SNeilBrown if (bd->entries == 0) 909b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 9106282cd56SNeilBrown bd->entries += 1; 911f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 9126282cd56SNeilBrown } 9136282cd56SNeilBrown 9141da177e4SLinus Torvalds static struct nfs4_delegation * 91586d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 91686d29b10SJ. Bruce Fields struct svc_fh *current_fh, 9178287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 9181da177e4SLinus Torvalds { 9191da177e4SLinus Torvalds struct nfs4_delegation *dp; 92002a3508dSTrond Myklebust long n; 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 92302a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 92402a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 92502a3508dSTrond Myklebust goto out_dec; 9266282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 92702a3508dSTrond Myklebust goto out_dec; 928d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 9295b2d21c1SNeilBrown if (dp == NULL) 93002a3508dSTrond Myklebust goto out_dec; 9316011695dSTrond Myklebust 9322a74aba7SJ. Bruce Fields /* 9332a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 9346136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 9356136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 9362a74aba7SJ. Bruce Fields */ 9372a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 938ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 939ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 9401da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 9418287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 9428287f009SSachin Bhamare get_clnt_odstate(odstate); 94399c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 944f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 945f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 9460162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 94786d29b10SJ. Bruce Fields get_nfs4_file(fp); 94886d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 9491da177e4SLinus Torvalds return dp; 95002a3508dSTrond Myklebust out_dec: 95102a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 95202a3508dSTrond Myklebust return NULL; 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds void 9566011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 9571da177e4SLinus Torvalds { 95811b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 9596011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 9606011695dSTrond Myklebust 9614770d722SJeff Layton might_lock(&clp->cl_lock); 9624770d722SJeff Layton 963a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 964b401be22SJeff Layton wake_up_all(&close_wq); 9656011695dSTrond Myklebust return; 966b401be22SJeff Layton } 9676011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 968624322f1SOlga Kornievskaia nfs4_free_cpntf_statelist(clp->net, s); 9694770d722SJeff Layton spin_unlock(&clp->cl_lock); 9706011695dSTrond Myklebust s->sc_free(s); 97111b9164aSTrond Myklebust if (fp) 97211b9164aSTrond Myklebust put_nfs4_file(fp); 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 9759767feb2SJeff Layton void 9769767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 9779767feb2SJeff Layton { 9789767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 9799767feb2SJeff Layton 9809767feb2SJeff Layton spin_lock(&stid->sc_lock); 9819767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 9829767feb2SJeff Layton src->si_generation = 1; 9839767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 9849767feb2SJeff Layton spin_unlock(&stid->sc_lock); 9859767feb2SJeff Layton } 9869767feb2SJeff Layton 987353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 9881da177e4SLinus Torvalds { 989eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 990353601e7SJ. Bruce Fields 991353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 992353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 993eb82dd39SJeff Layton swap(nf, fp->fi_deleg_file); 994353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 995353601e7SJ. Bruce Fields 996eb82dd39SJeff Layton if (nf) 997eb82dd39SJeff Layton nfsd_file_put(nf); 998353601e7SJ. Bruce Fields } 999353601e7SJ. Bruce Fields 1000353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 1001353601e7SJ. Bruce Fields { 1002cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 1003eb82dd39SJeff Layton struct nfsd_file *nf = fp->fi_deleg_file; 1004417c6629SJeff Layton 1005b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 1006b8232d33SJ. Bruce Fields 1007eb82dd39SJeff Layton vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); 1008353601e7SJ. Bruce Fields put_deleg_file(fp); 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 10110af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 10120af6e690SJ. Bruce Fields { 10130af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 1014353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 10150af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 10160af6e690SJ. Bruce Fields } 10170af6e690SJ. Bruce Fields 1018cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 10196136d2b4SJ. Bruce Fields { 10203abdb607SJ. Bruce Fields s->sc_type = 0; 10216136d2b4SJ. Bruce Fields } 10226136d2b4SJ. Bruce Fields 102334ed9872SAndrew Elble /** 102468b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 102534ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 102634ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 102734ed9872SAndrew Elble * 102834ed9872SAndrew Elble * Return: 102968b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 103034ed9872SAndrew Elble */ 103134ed9872SAndrew Elble 103268b18f52SJ. Bruce Fields static bool 103368b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 1034931ee56cSBenny Halevy { 103534ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 103634ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 103734ed9872SAndrew Elble 1038cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 1039417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 1040931ee56cSBenny Halevy 104134ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 104234ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 104334ed9872SAndrew Elble if (clp == searchclp) { 104451d87bc2SFengguang Wu return true; 104534ed9872SAndrew Elble } 104634ed9872SAndrew Elble } 104751d87bc2SFengguang Wu return false; 104834ed9872SAndrew Elble } 104934ed9872SAndrew Elble 105034ed9872SAndrew Elble /** 105134ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 105234ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 105334ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 105434ed9872SAndrew Elble * 105534ed9872SAndrew Elble * Return: 105634ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 105734ed9872SAndrew Elble * 105834ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 105934ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 106034ed9872SAndrew Elble * 106134ed9872SAndrew Elble */ 106234ed9872SAndrew Elble 106334ed9872SAndrew Elble static int 106434ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 106534ed9872SAndrew Elble { 106634ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 106734ed9872SAndrew Elble 106834ed9872SAndrew Elble lockdep_assert_held(&state_lock); 106934ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 107034ed9872SAndrew Elble 107168b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 107268b18f52SJ. Bruce Fields return -EAGAIN; 1073a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 10743fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 1075931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 107634ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 107734ed9872SAndrew Elble return 0; 1078931ee56cSBenny Halevy } 1079931ee56cSBenny Halevy 10803fcbbd24SJeff Layton static bool 108142690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 10821da177e4SLinus Torvalds { 108311b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 108402e1215fSJeff Layton 108542690676SJeff Layton lockdep_assert_held(&state_lock); 108642690676SJeff Layton 10873fcbbd24SJeff Layton if (list_empty(&dp->dl_perfile)) 10883fcbbd24SJeff Layton return false; 10893fcbbd24SJeff Layton 1090b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 1091d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 1092d55a166cSJeff Layton ++dp->dl_time; 1093417c6629SJeff Layton spin_lock(&fp->fi_lock); 1094931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 10951da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 109602e1215fSJeff Layton list_del_init(&dp->dl_perfile); 109702e1215fSJeff Layton spin_unlock(&fp->fi_lock); 10983fcbbd24SJeff Layton return true; 1099cbf7a75bSJ. Bruce Fields } 11003bd64a5bSJ. Bruce Fields 11013bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 11023bd64a5bSJ. Bruce Fields { 11033fcbbd24SJeff Layton bool unhashed; 11043fcbbd24SJeff Layton 110542690676SJeff Layton spin_lock(&state_lock); 11063fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 110742690676SJeff Layton spin_unlock(&state_lock); 11080af6e690SJ. Bruce Fields if (unhashed) 11090af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 11103fcbbd24SJeff Layton } 11113bd64a5bSJ. Bruce Fields 11123bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 11133bd64a5bSJ. Bruce Fields { 11143bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 11153bd64a5bSJ. Bruce Fields 11162d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 11172d4a532dSJeff Layton 11180af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 11193bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 11200af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 11212d4a532dSJeff Layton spin_lock(&clp->cl_lock); 11222d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 11232d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 11243bd64a5bSJ. Bruce Fields } 11250af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 11263bd64a5bSJ. Bruce Fields } 11273bd64a5bSJ. Bruce Fields 11281da177e4SLinus Torvalds /* 11291da177e4SLinus Torvalds * SETCLIENTID state 11301da177e4SLinus Torvalds */ 11311da177e4SLinus Torvalds 1132ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1133ddc04c41SJ. Bruce Fields { 1134ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1135ddc04c41SJ. Bruce Fields } 1136ddc04c41SJ. Bruce Fields 11376b189105SScott Mayhew static unsigned int clientstr_hashval(struct xdr_netobj name) 1138ddc04c41SJ. Bruce Fields { 11396b189105SScott Mayhew return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; 1140ddc04c41SJ. Bruce Fields } 1141ddc04c41SJ. Bruce Fields 11421da177e4SLinus Torvalds /* 1143f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 1144f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 1145f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 1146f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 1147f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 1148f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 1149f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 1150f9d7562fSJ. Bruce Fields * 1151f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 1152f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 1153f9d7562fSJ. Bruce Fields * 1154f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 1155f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 1156f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 1157f9d7562fSJ. Bruce Fields * 1158f9d7562fSJ. Bruce Fields * which we should reject. 1159f9d7562fSJ. Bruce Fields */ 11605ae037e5SJeff Layton static unsigned int 11615ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 1162f9d7562fSJ. Bruce Fields int i; 11635ae037e5SJeff Layton unsigned int access = 0; 1164f9d7562fSJ. Bruce Fields 1165f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 1166f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 11675ae037e5SJeff Layton access |= i; 1168f9d7562fSJ. Bruce Fields } 11695ae037e5SJeff Layton return access; 1170f9d7562fSJ. Bruce Fields } 1171f9d7562fSJ. Bruce Fields 117282c5ff1bSJeff Layton /* set share access for a given stateid */ 117382c5ff1bSJeff Layton static inline void 117482c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 117582c5ff1bSJeff Layton { 1176c11c591fSJeff Layton unsigned char mask = 1 << access; 1177c11c591fSJeff Layton 1178c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1179c11c591fSJeff Layton stp->st_access_bmap |= mask; 118082c5ff1bSJeff Layton } 118182c5ff1bSJeff Layton 118282c5ff1bSJeff Layton /* clear share access for a given stateid */ 118382c5ff1bSJeff Layton static inline void 118482c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 118582c5ff1bSJeff Layton { 1186c11c591fSJeff Layton unsigned char mask = 1 << access; 1187c11c591fSJeff Layton 1188c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1189c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 119082c5ff1bSJeff Layton } 119182c5ff1bSJeff Layton 119282c5ff1bSJeff Layton /* test whether a given stateid has access */ 119382c5ff1bSJeff Layton static inline bool 119482c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 119582c5ff1bSJeff Layton { 1196c11c591fSJeff Layton unsigned char mask = 1 << access; 1197c11c591fSJeff Layton 1198c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 119982c5ff1bSJeff Layton } 120082c5ff1bSJeff Layton 1201ce0fc43cSJeff Layton /* set share deny for a given stateid */ 1202ce0fc43cSJeff Layton static inline void 1203c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 1204ce0fc43cSJeff Layton { 1205c11c591fSJeff Layton unsigned char mask = 1 << deny; 1206c11c591fSJeff Layton 1207c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1208c11c591fSJeff Layton stp->st_deny_bmap |= mask; 1209ce0fc43cSJeff Layton } 1210ce0fc43cSJeff Layton 1211ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 1212ce0fc43cSJeff Layton static inline void 1213c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 1214ce0fc43cSJeff Layton { 1215c11c591fSJeff Layton unsigned char mask = 1 << deny; 1216c11c591fSJeff Layton 1217c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1218c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 1219ce0fc43cSJeff Layton } 1220ce0fc43cSJeff Layton 1221ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 1222ce0fc43cSJeff Layton static inline bool 1223c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 1224ce0fc43cSJeff Layton { 1225c11c591fSJeff Layton unsigned char mask = 1 << deny; 1226c11c591fSJeff Layton 1227c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 1228f9d7562fSJ. Bruce Fields } 1229f9d7562fSJ. Bruce Fields 1230f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 1231f9d7562fSJ. Bruce Fields { 12328f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 1233f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 1234f9d7562fSJ. Bruce Fields return O_RDONLY; 1235f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 1236f9d7562fSJ. Bruce Fields return O_WRONLY; 1237f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 1238f9d7562fSJ. Bruce Fields return O_RDWR; 1239f9d7562fSJ. Bruce Fields } 1240063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 1241063b0fb9SJ. Bruce Fields return O_RDONLY; 1242f9d7562fSJ. Bruce Fields } 1243f9d7562fSJ. Bruce Fields 1244baeb4ff0SJeff Layton /* 1245baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1246baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1247baeb4ff0SJeff Layton */ 1248baeb4ff0SJeff Layton static void 1249baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1250baeb4ff0SJeff Layton { 1251baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1252baeb4ff0SJeff Layton 1253baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1254baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1255baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1256baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1257baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1258baeb4ff0SJeff Layton } 1259baeb4ff0SJeff Layton 1260baeb4ff0SJeff Layton static void 1261baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1262baeb4ff0SJeff Layton { 1263baeb4ff0SJeff Layton int i; 1264baeb4ff0SJeff Layton bool change = false; 1265baeb4ff0SJeff Layton 1266baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1267baeb4ff0SJeff Layton if ((i & deny) != i) { 1268baeb4ff0SJeff Layton change = true; 1269baeb4ff0SJeff Layton clear_deny(i, stp); 1270baeb4ff0SJeff Layton } 1271baeb4ff0SJeff Layton } 1272baeb4ff0SJeff Layton 1273baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1274baeb4ff0SJeff Layton if (change) 127511b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1276baeb4ff0SJeff Layton } 1277baeb4ff0SJeff Layton 127882c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 127982c5ff1bSJeff Layton static void 128082c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 128182c5ff1bSJeff Layton { 128282c5ff1bSJeff Layton int i; 128311b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1284baeb4ff0SJeff Layton 1285baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1286baeb4ff0SJeff Layton recalculate_deny_mode(fp); 128782c5ff1bSJeff Layton 128882c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 128982c5ff1bSJeff Layton if (test_access(i, stp)) 129011b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 129182c5ff1bSJeff Layton clear_access(i, stp); 129282c5ff1bSJeff Layton } 129382c5ff1bSJeff Layton } 129482c5ff1bSJeff Layton 1295d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1296d50ffdedSKinglong Mee { 1297d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1298d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1299d50ffdedSKinglong Mee } 1300d50ffdedSKinglong Mee 13016b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 13026b180f0bSJeff Layton { 1303a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1304a819ecc1SJeff Layton 1305a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1306a819ecc1SJeff Layton 1307a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 13086b180f0bSJeff Layton return; 13098f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1310a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1311d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 13126b180f0bSJeff Layton } 13136b180f0bSJeff Layton 1314a451b123STrond Myklebust static bool 1315a451b123STrond Myklebust nfs4_ol_stateid_unhashed(const struct nfs4_ol_stateid *stp) 1316a451b123STrond Myklebust { 1317a451b123STrond Myklebust return list_empty(&stp->st_perfile); 1318a451b123STrond Myklebust } 1319a451b123STrond Myklebust 1320e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1321529d7b2aSJ. Bruce Fields { 132211b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 13231d31a253STrond Myklebust 13241c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 13251c755dc1SJeff Layton 1326e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1327e8568739SJeff Layton return false; 1328e8568739SJeff Layton 13291d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1330e8568739SJeff Layton list_del_init(&stp->st_perfile); 13311d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1332529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1333e8568739SJeff Layton return true; 1334529d7b2aSJ. Bruce Fields } 1335529d7b2aSJ. Bruce Fields 13366011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1337529d7b2aSJ. Bruce Fields { 13386011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 13394665e2baSJ. Bruce Fields 13408287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 13416011695dSTrond Myklebust release_all_access(stp); 1342d3134b10SJeff Layton if (stp->st_stateowner) 1343d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 13446011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1345529d7b2aSJ. Bruce Fields } 1346529d7b2aSJ. Bruce Fields 1347b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1348529d7b2aSJ. Bruce Fields { 1349b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1350b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1351eb82dd39SJeff Layton struct nfsd_file *nf; 1352529d7b2aSJ. Bruce Fields 1353eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 1354eb82dd39SJeff Layton if (nf) { 1355eb82dd39SJeff Layton get_file(nf->nf_file); 1356eb82dd39SJeff Layton filp_close(nf->nf_file, (fl_owner_t)lo); 1357eb82dd39SJeff Layton nfsd_file_put(nf); 1358eb82dd39SJeff Layton } 1359b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1360b49e084dSJeff Layton } 1361b49e084dSJeff Layton 13622c41beb0SJeff Layton /* 13632c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 13642c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 13652c41beb0SJeff Layton * reaplist for later destruction. 13662c41beb0SJeff Layton */ 13672c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 13682c41beb0SJeff Layton struct list_head *reaplist) 13692c41beb0SJeff Layton { 13702c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 13712c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 13722c41beb0SJeff Layton 13732c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 13742c41beb0SJeff Layton 13752c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 13762c41beb0SJeff Layton 1377a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 13782c41beb0SJeff Layton wake_up_all(&close_wq); 13792c41beb0SJeff Layton return; 13802c41beb0SJeff Layton } 13812c41beb0SJeff Layton 13822c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 13832c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 13842c41beb0SJeff Layton } 13852c41beb0SJeff Layton 1386e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 13873c1c995cSJeff Layton { 1388f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 13893c1c995cSJeff Layton 1390a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1391a451b123STrond Myklebust return false; 13923c1c995cSJeff Layton list_del_init(&stp->st_locks); 1393cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1394a451b123STrond Myklebust return true; 13953c1c995cSJeff Layton } 13963c1c995cSJeff Layton 13975adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1398b49e084dSJeff Layton { 1399f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1400e8568739SJeff Layton bool unhashed; 14011c755dc1SJeff Layton 1402f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1403e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1404f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1405e8568739SJeff Layton if (unhashed) 14066011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1407529d7b2aSJ. Bruce Fields } 1408529d7b2aSJ. Bruce Fields 1409c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1410529d7b2aSJ. Bruce Fields { 1411d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1412c58c6610STrond Myklebust 1413d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1414c58c6610STrond Myklebust 14158f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 14168f4b54c5SJeff Layton } 14178f4b54c5SJeff Layton 14182c41beb0SJeff Layton /* 14192c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 14202c41beb0SJeff Layton * fully unhashed. 14212c41beb0SJeff Layton */ 14222c41beb0SJeff Layton static void 14232c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 14242c41beb0SJeff Layton { 14252c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1426fb94d766SKinglong Mee struct nfs4_file *fp; 14272c41beb0SJeff Layton 14282c41beb0SJeff Layton might_sleep(); 14292c41beb0SJeff Layton 14302c41beb0SJeff Layton while (!list_empty(reaplist)) { 14312c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 14322c41beb0SJeff Layton st_locks); 14332c41beb0SJeff Layton list_del(&stp->st_locks); 1434fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 14352c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1436fb94d766SKinglong Mee if (fp) 1437fb94d766SKinglong Mee put_nfs4_file(fp); 14382c41beb0SJeff Layton } 14392c41beb0SJeff Layton } 14402c41beb0SJeff Layton 1441d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1442d83017f9SJeff Layton struct list_head *reaplist) 14433c87b9b7STrond Myklebust { 14443c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 14453c87b9b7STrond Myklebust 1446e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1447e8568739SJeff Layton 14483c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 14493c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 14503c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1451e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1452d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1453529d7b2aSJ. Bruce Fields } 1454529d7b2aSJ. Bruce Fields } 1455529d7b2aSJ. Bruce Fields 1456e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1457d83017f9SJeff Layton struct list_head *reaplist) 14582283963fSJ. Bruce Fields { 14592c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 14602c41beb0SJeff Layton 1461a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1462a451b123STrond Myklebust return false; 1463d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1464a451b123STrond Myklebust return true; 146538c387b5SJ. Bruce Fields } 146638c387b5SJ. Bruce Fields 146738c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 146838c387b5SJ. Bruce Fields { 14692c41beb0SJeff Layton LIST_HEAD(reaplist); 14702c41beb0SJeff Layton 14712c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1472e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 14732c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 14742c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 14752c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 14762283963fSJ. Bruce Fields } 14772283963fSJ. Bruce Fields 14787ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1479f1d110caSJ. Bruce Fields { 1480d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 14817ffb5880STrond Myklebust 1482d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 14837ffb5880STrond Myklebust 14848f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 14858f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1486f1d110caSJ. Bruce Fields } 1487f1d110caSJ. Bruce Fields 1488f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1489f7a4d872SJ. Bruce Fields { 1490217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1491217526e7SJeff Layton nfsd_net_id); 1492217526e7SJeff Layton struct nfs4_ol_stateid *s; 1493f7a4d872SJ. Bruce Fields 1494217526e7SJeff Layton spin_lock(&nn->client_lock); 1495217526e7SJeff Layton s = oo->oo_last_closed_stid; 1496f7a4d872SJ. Bruce Fields if (s) { 1497d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1498f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1499f7a4d872SJ. Bruce Fields } 1500217526e7SJeff Layton spin_unlock(&nn->client_lock); 1501217526e7SJeff Layton if (s) 1502217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1503f7a4d872SJ. Bruce Fields } 1504f7a4d872SJ. Bruce Fields 15052c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 15068f4b54c5SJeff Layton { 15078f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1508d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 15092c41beb0SJeff Layton struct list_head reaplist; 15107ffb5880STrond Myklebust 15112c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 15127ffb5880STrond Myklebust 1513d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 15147ffb5880STrond Myklebust unhash_openowner_locked(oo); 15152c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 15162c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 15172c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1518e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 15192c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 15202c41beb0SJeff Layton } 1521d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 15222c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1523f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 15246b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1525f1d110caSJ. Bruce Fields } 1526f1d110caSJ. Bruce Fields 15275282fd72SMarc Eshel static inline int 15285282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 15295282fd72SMarc Eshel { 15305282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 15315282fd72SMarc Eshel 15325282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 15335282fd72SMarc Eshel } 15345282fd72SMarc Eshel 1535135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 15365282fd72SMarc Eshel static inline void 15375282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 15385282fd72SMarc Eshel { 15395282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 15405282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 15415282fd72SMarc Eshel } 15428f199b82STrond Myklebust #else 15438f199b82STrond Myklebust static inline void 15448f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 15458f199b82STrond Myklebust { 15468f199b82STrond Myklebust } 15478f199b82STrond Myklebust #endif 15488f199b82STrond Myklebust 15499411b1d4SJ. Bruce Fields /* 15509411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 15519411b1d4SJ. Bruce Fields * won't be used for replay. 15529411b1d4SJ. Bruce Fields */ 15539411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 15549411b1d4SJ. Bruce Fields { 15559411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 15569411b1d4SJ. Bruce Fields 15579411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 15589411b1d4SJ. Bruce Fields return; 15599411b1d4SJ. Bruce Fields 15609411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 156158fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 15629411b1d4SJ. Bruce Fields return; 15639411b1d4SJ. Bruce Fields } 15649411b1d4SJ. Bruce Fields if (!so) 15659411b1d4SJ. Bruce Fields return; 15669411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 15679411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 15689411b1d4SJ. Bruce Fields so->so_seqid++; 15699411b1d4SJ. Bruce Fields return; 15709411b1d4SJ. Bruce Fields } 15715282fd72SMarc Eshel 1572ec6b5d7bSAndy Adamson static void 1573ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1574ec6b5d7bSAndy Adamson { 1575ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1576ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1577ec6b5d7bSAndy Adamson 1578ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1579ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1580ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1581ec6b5d7bSAndy Adamson sid->reserved = 0; 1582ec6b5d7bSAndy Adamson } 1583ec6b5d7bSAndy Adamson 1584ec6b5d7bSAndy Adamson /* 1585a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1586a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1587a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1588a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1589a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1590a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1591a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1592a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1593a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1594a649637cSAndy Adamson * for the SEQUENCE op response: 1595ec6b5d7bSAndy Adamson */ 1596a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1597a649637cSAndy Adamson 1598557ce264SAndy Adamson static void 1599557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1600557ce264SAndy Adamson { 1601557ce264SAndy Adamson int i; 1602557ce264SAndy Adamson 160353da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 160453da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1605557ce264SAndy Adamson kfree(ses->se_slots[i]); 1606557ce264SAndy Adamson } 160753da6a53SJ. Bruce Fields } 1608557ce264SAndy Adamson 1609efe0cb6dSJ. Bruce Fields /* 1610efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1611efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1612efe0cb6dSJ. Bruce Fields */ 161355c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1614efe0cb6dSJ. Bruce Fields { 161555c760cfSJ. Bruce Fields u32 size; 1616efe0cb6dSJ. Bruce Fields 161755c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 161855c760cfSJ. Bruce Fields size = 0; 161955c760cfSJ. Bruce Fields else 162055c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 162155c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1622557ce264SAndy Adamson } 1623557ce264SAndy Adamson 16245b6feee9SJ. Bruce Fields /* 16255b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 16265b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 162742b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 16285b6feee9SJ. Bruce Fields */ 16292030ca56SNeilBrown static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 16305b6feee9SJ. Bruce Fields { 163155c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 163255c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 1633c54f24e3SJ. Bruce Fields unsigned long avail, total_avail; 16342030ca56SNeilBrown unsigned int scale_factor; 16355b6feee9SJ. Bruce Fields 16365b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 16377f49fd5dSNeilBrown if (nfsd_drc_max_mem > nfsd_drc_mem_used) 1638c54f24e3SJ. Bruce Fields total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 16397f49fd5dSNeilBrown else 16407f49fd5dSNeilBrown /* We have handed out more space than we chose in 16417f49fd5dSNeilBrown * set_max_drc() to allow. That isn't really a 16427f49fd5dSNeilBrown * problem as long as that doesn't make us think we 16437f49fd5dSNeilBrown * have lots more due to integer overflow. 16447f49fd5dSNeilBrown */ 16457f49fd5dSNeilBrown total_avail = 0; 1646c54f24e3SJ. Bruce Fields avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1647de766e57SJ. Bruce Fields /* 16482030ca56SNeilBrown * Never use more than a fraction of the remaining memory, 16497f49fd5dSNeilBrown * unless it's the only way to give this client a slot. 16502030ca56SNeilBrown * The chosen fraction is either 1/8 or 1/number of threads, 16512030ca56SNeilBrown * whichever is smaller. This ensures there are adequate 16522030ca56SNeilBrown * slots to support multiple clients per thread. 16537f49fd5dSNeilBrown * Give the client one slot even if that would require 16547f49fd5dSNeilBrown * over-allocation--it is better than failure. 1655de766e57SJ. Bruce Fields */ 16562030ca56SNeilBrown scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); 16572030ca56SNeilBrown 16582030ca56SNeilBrown avail = clamp_t(unsigned long, avail, slotsize, 16592030ca56SNeilBrown total_avail/scale_factor); 16605b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 16617f49fd5dSNeilBrown num = max_t(int, num, 1); 16625b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 16635b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 16645b6feee9SJ. Bruce Fields 16655b6feee9SJ. Bruce Fields return num; 16665b6feee9SJ. Bruce Fields } 16675b6feee9SJ. Bruce Fields 166855c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 16695b6feee9SJ. Bruce Fields { 167055c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 167155c760cfSJ. Bruce Fields 16725b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 167355c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 16745b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 16755b6feee9SJ. Bruce Fields } 16765b6feee9SJ. Bruce Fields 167760810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 167860810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 16795b6feee9SJ. Bruce Fields { 168060810e54SKinglong Mee int numslots = fattrs->maxreqs; 168160810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 16825b6feee9SJ. Bruce Fields struct nfsd4_session *new; 16835b6feee9SJ. Bruce Fields int mem, i; 1684ec6b5d7bSAndy Adamson 1685c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1686ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 16875b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1688ec6b5d7bSAndy Adamson 16895b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 16906c18ba9fSAlexandros Batsakis if (!new) 16915b6feee9SJ. Bruce Fields return NULL; 1692ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 16935b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 169455c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 16955b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1696ec6b5d7bSAndy Adamson goto out_free; 1697ec6b5d7bSAndy Adamson } 169860810e54SKinglong Mee 169960810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 170060810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 170160810e54SKinglong Mee 17025b6feee9SJ. Bruce Fields return new; 17035b6feee9SJ. Bruce Fields out_free: 17045b6feee9SJ. Bruce Fields while (i--) 17055b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 17065b6feee9SJ. Bruce Fields kfree(new); 17075b6feee9SJ. Bruce Fields return NULL; 17085b6feee9SJ. Bruce Fields } 17095b6feee9SJ. Bruce Fields 171019cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 171119cf5c02SJ. Bruce Fields { 171219cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 171319cf5c02SJ. Bruce Fields kfree(c); 171419cf5c02SJ. Bruce Fields } 171519cf5c02SJ. Bruce Fields 171619cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 171719cf5c02SJ. Bruce Fields { 171819cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 171919cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 172019cf5c02SJ. Bruce Fields 172119cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 172219cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 172319cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 172419cf5c02SJ. Bruce Fields free_conn(c); 172519cf5c02SJ. Bruce Fields } 1726eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 17272e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 172819cf5c02SJ. Bruce Fields } 172919cf5c02SJ. Bruce Fields 1730d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1731c7662518SJ. Bruce Fields { 1732c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1733c7662518SJ. Bruce Fields 1734c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1735c7662518SJ. Bruce Fields if (!conn) 1736db90681dSJ. Bruce Fields return NULL; 1737c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1738c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1739d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1740db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1741db90681dSJ. Bruce Fields return conn; 1742db90681dSJ. Bruce Fields } 1743db90681dSJ. Bruce Fields 1744328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1745328ead28SJ. Bruce Fields { 1746328ead28SJ. Bruce Fields conn->cn_session = ses; 1747328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1748328ead28SJ. Bruce Fields } 1749328ead28SJ. Bruce Fields 1750db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1751db90681dSJ. Bruce Fields { 1752db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1753c7662518SJ. Bruce Fields 1754c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1755328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1756c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1757db90681dSJ. Bruce Fields } 1758c7662518SJ. Bruce Fields 175921b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1760db90681dSJ. Bruce Fields { 176119cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 176221b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1763db90681dSJ. Bruce Fields } 1764db90681dSJ. Bruce Fields 1765e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1766db90681dSJ. Bruce Fields { 176721b75b01SJ. Bruce Fields int ret; 1768db90681dSJ. Bruce Fields 1769db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 177021b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 177121b75b01SJ. Bruce Fields if (ret) 177221b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 177321b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 177457a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 177557a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1776c7662518SJ. Bruce Fields } 1777c7662518SJ. Bruce Fields 1778e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 17791d1bc8f2SJ. Bruce Fields { 17801d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 17811d1bc8f2SJ. Bruce Fields 1782e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 17831d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1784e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 17851d1bc8f2SJ. Bruce Fields } 17861d1bc8f2SJ. Bruce Fields 17871d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 178819cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1789c7662518SJ. Bruce Fields { 179019cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 179119cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 179219cf5c02SJ. Bruce Fields 179319cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 179419cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 179519cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 179619cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 179719cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 179819cf5c02SJ. Bruce Fields 179919cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 180019cf5c02SJ. Bruce Fields free_conn(c); 180119cf5c02SJ. Bruce Fields 180219cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 180319cf5c02SJ. Bruce Fields } 180419cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1805c7662518SJ. Bruce Fields } 1806c7662518SJ. Bruce Fields 18071377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 18081377b69eSJ. Bruce Fields { 18091377b69eSJ. Bruce Fields free_session_slots(ses); 18101377b69eSJ. Bruce Fields kfree(ses); 18111377b69eSJ. Bruce Fields } 18121377b69eSJ. Bruce Fields 181366b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1814508dc6e1SBenny Halevy { 1815c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 181655c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1817c7662518SJ. Bruce Fields __free_session(ses); 1818a827bcb2SJ. Bruce Fields } 1819ec6b5d7bSAndy Adamson 1820135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1821a827bcb2SJ. Bruce Fields { 1822a827bcb2SJ. Bruce Fields int idx; 18231872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1824a827bcb2SJ. Bruce Fields 1825ec6b5d7bSAndy Adamson new->se_client = clp; 1826ec6b5d7bSAndy Adamson gen_sessionid(new); 1827ec6b5d7bSAndy Adamson 1828c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1829c7662518SJ. Bruce Fields 1830ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1831ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 18328b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1833c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 183466b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 18355b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 18361872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 18374c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1838ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 18394c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 184060810e54SKinglong Mee 1841b0d2e42cSChuck Lever { 1842edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1843dcbeaa68SJ. Bruce Fields /* 1844dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1845dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1846dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1847dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1848dcbeaa68SJ. Bruce Fields * future: 1849dcbeaa68SJ. Bruce Fields */ 1850edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1851edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1852edd76786SJ. Bruce Fields } 1853ec6b5d7bSAndy Adamson } 1854ec6b5d7bSAndy Adamson 18559089f1b4SBenny Halevy /* caller must hold client_lock */ 18565282fd72SMarc Eshel static struct nfsd4_session * 1857d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 18585282fd72SMarc Eshel { 18595282fd72SMarc Eshel struct nfsd4_session *elem; 18605282fd72SMarc Eshel int idx; 18611872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 18625282fd72SMarc Eshel 18630a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 18640a880a28STrond Myklebust 18655282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 18665282fd72SMarc Eshel idx = hash_sessionid(sessionid); 18675282fd72SMarc Eshel /* Search in the appropriate list */ 18681872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 18695282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 18705282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 18715282fd72SMarc Eshel return elem; 18725282fd72SMarc Eshel } 18735282fd72SMarc Eshel } 18745282fd72SMarc Eshel 18755282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 18765282fd72SMarc Eshel return NULL; 18775282fd72SMarc Eshel } 18785282fd72SMarc Eshel 1879d4e19e70STrond Myklebust static struct nfsd4_session * 1880d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1881d4e19e70STrond Myklebust __be32 *ret) 1882d4e19e70STrond Myklebust { 1883d4e19e70STrond Myklebust struct nfsd4_session *session; 1884d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1885d4e19e70STrond Myklebust 1886d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1887d4e19e70STrond Myklebust if (!session) 1888d4e19e70STrond Myklebust goto out; 1889d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1890d4e19e70STrond Myklebust if (status) 1891d4e19e70STrond Myklebust session = NULL; 1892d4e19e70STrond Myklebust out: 1893d4e19e70STrond Myklebust *ret = status; 1894d4e19e70STrond Myklebust return session; 1895d4e19e70STrond Myklebust } 1896d4e19e70STrond Myklebust 18979089f1b4SBenny Halevy /* caller must hold client_lock */ 18987116ed6bSAndy Adamson static void 18995282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 19007116ed6bSAndy Adamson { 19010a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 19020a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 19030a880a28STrond Myklebust 19040a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 19050a880a28STrond Myklebust 19067116ed6bSAndy Adamson list_del(&ses->se_hash); 19074c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 19087116ed6bSAndy Adamson list_del(&ses->se_perclnt); 19094c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 19105282fd72SMarc Eshel } 19115282fd72SMarc Eshel 19121da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 19131da177e4SLinus Torvalds static int 19142c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 19151da177e4SLinus Torvalds { 1916bbc7f33aSJ. Bruce Fields /* 1917bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 1918bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 1919bbc7f33aSJ. Bruce Fields * a safe assumption: 1920bbc7f33aSJ. Bruce Fields */ 1921bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 19221da177e4SLinus Torvalds return 0; 1923dd5e3fbcSChuck Lever trace_nfsd_clid_stale(clid); 19241da177e4SLinus Torvalds return 1; 19251da177e4SLinus Torvalds } 19261da177e4SLinus Torvalds 19271da177e4SLinus Torvalds /* 19281da177e4SLinus Torvalds * XXX Should we use a slab cache ? 19291da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 19301da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 19311da177e4SLinus Torvalds */ 193235bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 19331da177e4SLinus Torvalds { 19341da177e4SLinus Torvalds struct nfs4_client *clp; 1935d4f0489fSTrond Myklebust int i; 19361da177e4SLinus Torvalds 19379258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 193835bba9a3SJ. Bruce Fields if (clp == NULL) 193935bba9a3SJ. Bruce Fields return NULL; 19406f4859b8SJ. Bruce Fields xdr_netobj_dup(&clp->cl_name, &name, GFP_KERNEL); 1941d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1942d4f0489fSTrond Myklebust goto err_no_name; 19436da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 19446da2ec56SKees Cook sizeof(struct list_head), 19456da2ec56SKees Cook GFP_KERNEL); 1946d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1947d4f0489fSTrond Myklebust goto err_no_hashtbl; 1948d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1949d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 19505694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 19515694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 195214ed14ccSJ. Bruce Fields atomic_set(&clp->cl_rpc_users, 0); 19535694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 19545694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 19555694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 19565694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 19575694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 19585694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 19599cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 19609cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 19619cf514ccSChristoph Hellwig #endif 1962e0639dc5SOlga Kornievskaia INIT_LIST_HEAD(&clp->async_copies); 1963e0639dc5SOlga Kornievskaia spin_lock_init(&clp->async_lock); 19645694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 19655694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 19661da177e4SLinus Torvalds return clp; 1967d4f0489fSTrond Myklebust err_no_hashtbl: 1968d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1969d4f0489fSTrond Myklebust err_no_name: 19709258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 1971d4f0489fSTrond Myklebust return NULL; 19721da177e4SLinus Torvalds } 19731da177e4SLinus Torvalds 197459f8e91bSJ. Bruce Fields static void __free_client(struct kref *k) 197559f8e91bSJ. Bruce Fields { 1976e8a79fb1SJ. Bruce Fields struct nfsdfs_client *c = container_of(k, struct nfsdfs_client, cl_ref); 1977e8a79fb1SJ. Bruce Fields struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs); 197859f8e91bSJ. Bruce Fields 197959f8e91bSJ. Bruce Fields free_svc_cred(&clp->cl_cred); 198059f8e91bSJ. Bruce Fields kfree(clp->cl_ownerstr_hashtbl); 198159f8e91bSJ. Bruce Fields kfree(clp->cl_name.data); 198279123444SJ. Bruce Fields kfree(clp->cl_nii_domain.data); 198379123444SJ. Bruce Fields kfree(clp->cl_nii_name.data); 198459f8e91bSJ. Bruce Fields idr_destroy(&clp->cl_stateids); 198559f8e91bSJ. Bruce Fields kmem_cache_free(client_slab, clp); 198659f8e91bSJ. Bruce Fields } 198759f8e91bSJ. Bruce Fields 1988297e57a2SYueHaibing static void drop_client(struct nfs4_client *clp) 198959f8e91bSJ. Bruce Fields { 1990e8a79fb1SJ. Bruce Fields kref_put(&clp->cl_nfsdfs.cl_ref, __free_client); 199159f8e91bSJ. Bruce Fields } 199259f8e91bSJ. Bruce Fields 19934dd86e15STrond Myklebust static void 19941da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 19951da177e4SLinus Torvalds { 1996792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 1997792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 1998792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 1999792c95ddSJ. Bruce Fields se_perclnt); 2000792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 200166b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 200266b2b9b2SJ. Bruce Fields free_session(ses); 2003792c95ddSJ. Bruce Fields } 20044cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 200589c905beSJ. Bruce Fields if (clp->cl_nfsd_dentry) { 2006e8a79fb1SJ. Bruce Fields nfsd_client_rmdir(clp->cl_nfsd_dentry); 200789c905beSJ. Bruce Fields clp->cl_nfsd_dentry = NULL; 200889c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 200989c905beSJ. Bruce Fields } 201059f8e91bSJ. Bruce Fields drop_client(clp); 20111da177e4SLinus Torvalds } 20121da177e4SLinus Torvalds 201384d38ac9SBenny Halevy /* must be called under the client_lock */ 20144beb345bSTrond Myklebust static void 201584d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 201684d38ac9SBenny Halevy { 20174beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2018792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2019792c95ddSJ. Bruce Fields 20200a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20210a880a28STrond Myklebust 20224beb345bSTrond Myklebust /* Mark the client as expired! */ 20234beb345bSTrond Myklebust clp->cl_time = 0; 20244beb345bSTrond Myklebust /* Make it invisible */ 20254beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 20264beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 20274beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 20284beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 20294beb345bSTrond Myklebust else 20304beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 20314beb345bSTrond Myklebust } 20324beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 20334c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 2034792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 2035792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 20364c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 203784d38ac9SBenny Halevy } 203884d38ac9SBenny Halevy 20391da177e4SLinus Torvalds static void 20404beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 20414beb345bSTrond Myklebust { 20424beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20434beb345bSTrond Myklebust 20444beb345bSTrond Myklebust spin_lock(&nn->client_lock); 20454beb345bSTrond Myklebust unhash_client_locked(clp); 20464beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 20474beb345bSTrond Myklebust } 20484beb345bSTrond Myklebust 204997403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 205097403d95SJeff Layton { 205114ed14ccSJ. Bruce Fields if (atomic_read(&clp->cl_rpc_users)) 205297403d95SJeff Layton return nfserr_jukebox; 205397403d95SJeff Layton unhash_client_locked(clp); 205497403d95SJeff Layton return nfs_ok; 205597403d95SJeff Layton } 205697403d95SJeff Layton 20574beb345bSTrond Myklebust static void 20584beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 20591da177e4SLinus Torvalds { 206068ef3bc3SJeff Layton int i; 2061fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 20621da177e4SLinus Torvalds struct nfs4_delegation *dp; 20631da177e4SLinus Torvalds struct list_head reaplist; 20641da177e4SLinus Torvalds 20651da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 2066cdc97505SBenny Halevy spin_lock(&state_lock); 2067ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 2068ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 20693fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 207042690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 20711da177e4SLinus Torvalds } 2072cdc97505SBenny Halevy spin_unlock(&state_lock); 20731da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 20741da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 207542690676SJeff Layton list_del_init(&dp->dl_recall_lru); 20760af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 20771da177e4SLinus Torvalds } 20782d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 2079c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 20802d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 20816011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 2082956c4feeSBenny Halevy } 2083ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 2084fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 2085b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 2086fe0750e5SJ. Bruce Fields release_openowner(oo); 20871da177e4SLinus Torvalds } 208868ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 208968ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 209068ef3bc3SJeff Layton 209168ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 209268ef3bc3SJeff Layton so_strhash) { 209368ef3bc3SJeff Layton /* Should be no openowners at this point */ 209468ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 209568ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 209668ef3bc3SJeff Layton } 209768ef3bc3SJeff Layton } 20989cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 2099e0639dc5SOlga Kornievskaia nfsd4_shutdown_copy(clp); 21006ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 21012bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 21022bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 2103b12a05cbSJ. Bruce Fields free_client(clp); 210489c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 21051da177e4SLinus Torvalds } 21061da177e4SLinus Torvalds 21074beb345bSTrond Myklebust static void 21084beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 21094beb345bSTrond Myklebust { 21104beb345bSTrond Myklebust unhash_client(clp); 21114beb345bSTrond Myklebust __destroy_client(clp); 21124beb345bSTrond Myklebust } 21134beb345bSTrond Myklebust 2114362063a5SScott Mayhew static void inc_reclaim_complete(struct nfs4_client *clp) 2115362063a5SScott Mayhew { 2116362063a5SScott Mayhew struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2117362063a5SScott Mayhew 2118362063a5SScott Mayhew if (!nn->track_reclaim_completes) 2119362063a5SScott Mayhew return; 2120362063a5SScott Mayhew if (!nfsd4_find_reclaim_client(clp->cl_name, nn)) 2121362063a5SScott Mayhew return; 2122362063a5SScott Mayhew if (atomic_inc_return(&nn->nr_reclaim_complete) == 2123362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) { 2124362063a5SScott Mayhew printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n", 2125362063a5SScott Mayhew clp->net->ns.inum); 2126362063a5SScott Mayhew nfsd4_end_grace(nn); 2127362063a5SScott Mayhew } 2128362063a5SScott Mayhew } 2129362063a5SScott Mayhew 21300d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 21310d22f68fSJ. Bruce Fields { 21324beb345bSTrond Myklebust unhash_client(clp); 21330d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 21344beb345bSTrond Myklebust __destroy_client(clp); 21350d22f68fSJ. Bruce Fields } 21360d22f68fSJ. Bruce Fields 213735bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 213835bba9a3SJ. Bruce Fields { 213935bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 214035bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 21411da177e4SLinus Torvalds } 21421da177e4SLinus Torvalds 214335bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 214435bba9a3SJ. Bruce Fields { 21451da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 21461da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 21471da177e4SLinus Torvalds } 21481da177e4SLinus Torvalds 214950043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 215050043859SJ. Bruce Fields { 21512f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 21522f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 21532f10fdcbSNeilBrown GFP_KERNEL); 21549abdda5dSChuck Lever target->cr_targ_princ = kstrdup(source->cr_targ_princ, GFP_KERNEL); 21552f10fdcbSNeilBrown if ((source->cr_principal && !target->cr_principal) || 21569abdda5dSChuck Lever (source->cr_raw_principal && !target->cr_raw_principal) || 21579abdda5dSChuck Lever (source->cr_targ_princ && !target->cr_targ_princ)) 21582f10fdcbSNeilBrown return -ENOMEM; 215950043859SJ. Bruce Fields 2160d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 21611da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 21621da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 21631da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 21641da177e4SLinus Torvalds get_group_info(target->cr_group_info); 21650dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 21660dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 21670dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 216803a4e1f6SJ. Bruce Fields return 0; 21691da177e4SLinus Torvalds } 21701da177e4SLinus Torvalds 2171ef17af2aSRasmus Villemoes static int 2172ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 2173ac55fdc4SJeff Layton { 2174ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2175ef17af2aSRasmus Villemoes return -1; 2176ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2177ef17af2aSRasmus Villemoes return 1; 2178ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2179ac55fdc4SJeff Layton } 2180ac55fdc4SJeff Layton 21811da177e4SLinus Torvalds static int 2182599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2183599e0a22SJ. Bruce Fields { 2184599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 21851da177e4SLinus Torvalds } 21861da177e4SLinus Torvalds 21871da177e4SLinus Torvalds static int 2188599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2189599e0a22SJ. Bruce Fields { 2190599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 21911da177e4SLinus Torvalds } 21921da177e4SLinus Torvalds 21938fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 21948fbba96eSJ. Bruce Fields { 21958fbba96eSJ. Bruce Fields int i; 21968fbba96eSJ. Bruce Fields 21978fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 21988fbba96eSJ. Bruce Fields return false; 21998fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 220081243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 22018fbba96eSJ. Bruce Fields return false; 22028fbba96eSJ. Bruce Fields return true; 22038fbba96eSJ. Bruce Fields } 22048fbba96eSJ. Bruce Fields 220568eb3508SJ. Bruce Fields /* 220668eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 220768eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 220868eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 220968eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 221068eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 221168eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 221268eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 221368eb3508SJ. Bruce Fields */ 221468eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 221568eb3508SJ. Bruce Fields { 221668eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 221768eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 221868eb3508SJ. Bruce Fields } 221968eb3508SJ. Bruce Fields 222068eb3508SJ. Bruce Fields 22215559b50aSVivek Trivedi static bool 2222599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2223599e0a22SJ. Bruce Fields { 222468eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 22256fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 22266fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 22278fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 22288fbba96eSJ. Bruce Fields return false; 22299abdda5dSChuck Lever /* XXX: check that cr_targ_princ fields match ? */ 22308fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 22318fbba96eSJ. Bruce Fields return true; 22328fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 22338fbba96eSJ. Bruce Fields return false; 22345559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 22351da177e4SLinus Torvalds } 22361da177e4SLinus Torvalds 223757266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 223857266a6eSJ. Bruce Fields { 223957266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 224057266a6eSJ. Bruce Fields u32 service; 224157266a6eSJ. Bruce Fields 2242c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2243c4720591SJ. Bruce Fields return false; 224457266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 224557266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 224657266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 224757266a6eSJ. Bruce Fields } 224857266a6eSJ. Bruce Fields 2249dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 225057266a6eSJ. Bruce Fields { 225157266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 225257266a6eSJ. Bruce Fields 225357266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 225457266a6eSJ. Bruce Fields return true; 225557266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 225657266a6eSJ. Bruce Fields return false; 225757266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 225857266a6eSJ. Bruce Fields return false; 2259414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2260414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2261414ca017SJ. Bruce Fields cr->cr_raw_principal); 226257266a6eSJ. Bruce Fields if (!cr->cr_principal) 226357266a6eSJ. Bruce Fields return false; 226457266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 226557266a6eSJ. Bruce Fields } 226657266a6eSJ. Bruce Fields 2267294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2268deda2faaSJ. Bruce Fields { 2269ab4684d1SChuck Lever __be32 verf[2]; 22701da177e4SLinus Torvalds 2271f419992cSJeff Layton /* 2272f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2273f419992cSJeff Layton * __force to keep sparse happy 2274f419992cSJeff Layton */ 22759104ae49SArnd Bergmann verf[0] = (__force __be32)(u32)ktime_get_real_seconds(); 227619311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2277ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 22781da177e4SLinus Torvalds } 22791da177e4SLinus Torvalds 2280294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2281294ac32eSJeff Layton { 22829cc76801SArnd Bergmann clp->cl_clientid.cl_boot = (u32)nn->boot_time; 2283294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2284294ac32eSJeff Layton gen_confirm(clp, nn); 2285294ac32eSJeff Layton } 2286294ac32eSJeff Layton 22874770d722SJeff Layton static struct nfs4_stid * 22884770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 22894581d140SJ. Bruce Fields { 22903abdb607SJ. Bruce Fields struct nfs4_stid *ret; 22913abdb607SJ. Bruce Fields 22923abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 22933abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 22943abdb607SJ. Bruce Fields return NULL; 22953abdb607SJ. Bruce Fields return ret; 22964581d140SJ. Bruce Fields } 22974d71ab87SJ. Bruce Fields 22984770d722SJeff Layton static struct nfs4_stid * 22994770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2300f459e453SJ. Bruce Fields { 2301f459e453SJ. Bruce Fields struct nfs4_stid *s; 2302f459e453SJ. Bruce Fields 23034770d722SJeff Layton spin_lock(&cl->cl_lock); 23044770d722SJeff Layton s = find_stateid_locked(cl, t); 23052d3f9668STrond Myklebust if (s != NULL) { 23062d3f9668STrond Myklebust if (typemask & s->sc_type) 2307a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 23082d3f9668STrond Myklebust else 23094770d722SJeff Layton s = NULL; 23102d3f9668STrond Myklebust } 23114770d722SJeff Layton spin_unlock(&cl->cl_lock); 23124d71ab87SJ. Bruce Fields return s; 23134581d140SJ. Bruce Fields } 23144581d140SJ. Bruce Fields 2315a204f25eSJ. Bruce Fields static struct nfs4_client *get_nfsdfs_clp(struct inode *inode) 2316a204f25eSJ. Bruce Fields { 2317a204f25eSJ. Bruce Fields struct nfsdfs_client *nc; 2318a204f25eSJ. Bruce Fields nc = get_nfsdfs_client(inode); 2319a204f25eSJ. Bruce Fields if (!nc) 2320a204f25eSJ. Bruce Fields return NULL; 2321a204f25eSJ. Bruce Fields return container_of(nc, struct nfs4_client, cl_nfsdfs); 2322a204f25eSJ. Bruce Fields } 2323a204f25eSJ. Bruce Fields 2324169319f1SJ. Bruce Fields static void seq_quote_mem(struct seq_file *m, char *data, int len) 2325169319f1SJ. Bruce Fields { 2326169319f1SJ. Bruce Fields seq_printf(m, "\""); 2327169319f1SJ. Bruce Fields seq_escape_mem_ascii(m, data, len); 2328169319f1SJ. Bruce Fields seq_printf(m, "\""); 2329169319f1SJ. Bruce Fields } 2330169319f1SJ. Bruce Fields 233197ad4031SJ. Bruce Fields static int client_info_show(struct seq_file *m, void *v) 233297ad4031SJ. Bruce Fields { 233397ad4031SJ. Bruce Fields struct inode *inode = m->private; 233497ad4031SJ. Bruce Fields struct nfs4_client *clp; 233597ad4031SJ. Bruce Fields u64 clid; 233697ad4031SJ. Bruce Fields 2337a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2338a204f25eSJ. Bruce Fields if (!clp) 233997ad4031SJ. Bruce Fields return -ENXIO; 234097ad4031SJ. Bruce Fields memcpy(&clid, &clp->cl_clientid, sizeof(clid)); 234197ad4031SJ. Bruce Fields seq_printf(m, "clientid: 0x%llx\n", clid); 2342169319f1SJ. Bruce Fields seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); 2343169319f1SJ. Bruce Fields seq_printf(m, "name: "); 2344169319f1SJ. Bruce Fields seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); 2345169319f1SJ. Bruce Fields seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); 234679123444SJ. Bruce Fields if (clp->cl_nii_domain.data) { 234779123444SJ. Bruce Fields seq_printf(m, "Implementation domain: "); 234879123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_domain.data, 234979123444SJ. Bruce Fields clp->cl_nii_domain.len); 235079123444SJ. Bruce Fields seq_printf(m, "\nImplementation name: "); 235179123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_name.data, clp->cl_nii_name.len); 2352e29f4703SArnd Bergmann seq_printf(m, "\nImplementation time: [%lld, %ld]\n", 235379123444SJ. Bruce Fields clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); 235479123444SJ. Bruce Fields } 235597ad4031SJ. Bruce Fields drop_client(clp); 235697ad4031SJ. Bruce Fields 235797ad4031SJ. Bruce Fields return 0; 235897ad4031SJ. Bruce Fields } 235997ad4031SJ. Bruce Fields 236097ad4031SJ. Bruce Fields static int client_info_open(struct inode *inode, struct file *file) 236197ad4031SJ. Bruce Fields { 236297ad4031SJ. Bruce Fields return single_open(file, client_info_show, inode); 236397ad4031SJ. Bruce Fields } 236497ad4031SJ. Bruce Fields 236597ad4031SJ. Bruce Fields static const struct file_operations client_info_fops = { 236697ad4031SJ. Bruce Fields .open = client_info_open, 236797ad4031SJ. Bruce Fields .read = seq_read, 236897ad4031SJ. Bruce Fields .llseek = seq_lseek, 236997ad4031SJ. Bruce Fields .release = single_release, 237097ad4031SJ. Bruce Fields }; 237197ad4031SJ. Bruce Fields 237278599c42SJ. Bruce Fields static void *states_start(struct seq_file *s, loff_t *pos) 237378599c42SJ. Bruce Fields __acquires(&clp->cl_lock) 237478599c42SJ. Bruce Fields { 237578599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 237678599c42SJ. Bruce Fields unsigned long id = *pos; 237778599c42SJ. Bruce Fields void *ret; 237878599c42SJ. Bruce Fields 237978599c42SJ. Bruce Fields spin_lock(&clp->cl_lock); 238078599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 238178599c42SJ. Bruce Fields *pos = id; 238278599c42SJ. Bruce Fields return ret; 238378599c42SJ. Bruce Fields } 238478599c42SJ. Bruce Fields 238578599c42SJ. Bruce Fields static void *states_next(struct seq_file *s, void *v, loff_t *pos) 238678599c42SJ. Bruce Fields { 238778599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 238878599c42SJ. Bruce Fields unsigned long id = *pos; 238978599c42SJ. Bruce Fields void *ret; 239078599c42SJ. Bruce Fields 239178599c42SJ. Bruce Fields id = *pos; 239278599c42SJ. Bruce Fields id++; 239378599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 239478599c42SJ. Bruce Fields *pos = id; 239578599c42SJ. Bruce Fields return ret; 239678599c42SJ. Bruce Fields } 239778599c42SJ. Bruce Fields 239878599c42SJ. Bruce Fields static void states_stop(struct seq_file *s, void *v) 239978599c42SJ. Bruce Fields __releases(&clp->cl_lock) 240078599c42SJ. Bruce Fields { 240178599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 240278599c42SJ. Bruce Fields 240378599c42SJ. Bruce Fields spin_unlock(&clp->cl_lock); 240478599c42SJ. Bruce Fields } 240578599c42SJ. Bruce Fields 2406580da465SAchilles Gaikwad static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f) 2407580da465SAchilles Gaikwad { 2408580da465SAchilles Gaikwad seq_printf(s, "filename: \"%pD2\"", f->nf_file); 2409580da465SAchilles Gaikwad } 2410580da465SAchilles Gaikwad 2411fd4f83fdSJeff Layton static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) 241278599c42SJ. Bruce Fields { 2413fd4f83fdSJeff Layton struct inode *inode = f->nf_inode; 241478599c42SJ. Bruce Fields 241578599c42SJ. Bruce Fields seq_printf(s, "superblock: \"%02x:%02x:%ld\"", 241678599c42SJ. Bruce Fields MAJOR(inode->i_sb->s_dev), 241778599c42SJ. Bruce Fields MINOR(inode->i_sb->s_dev), 241878599c42SJ. Bruce Fields inode->i_ino); 241978599c42SJ. Bruce Fields } 242078599c42SJ. Bruce Fields 242178599c42SJ. Bruce Fields static void nfs4_show_owner(struct seq_file *s, struct nfs4_stateowner *oo) 242278599c42SJ. Bruce Fields { 242378599c42SJ. Bruce Fields seq_printf(s, "owner: "); 242478599c42SJ. Bruce Fields seq_quote_mem(s, oo->so_owner.data, oo->so_owner.len); 242578599c42SJ. Bruce Fields } 242678599c42SJ. Bruce Fields 2427ace7ade4SJ. Bruce Fields static void nfs4_show_stateid(struct seq_file *s, stateid_t *stid) 2428ace7ade4SJ. Bruce Fields { 2429ee590d25SJ. Bruce Fields seq_printf(s, "0x%.8x", stid->si_generation); 2430ee590d25SJ. Bruce Fields seq_printf(s, "%12phN", &stid->si_opaque); 2431ace7ade4SJ. Bruce Fields } 2432ace7ade4SJ. Bruce Fields 243378599c42SJ. Bruce Fields static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) 243478599c42SJ. Bruce Fields { 243578599c42SJ. Bruce Fields struct nfs4_ol_stateid *ols; 243678599c42SJ. Bruce Fields struct nfs4_file *nf; 2437fd4f83fdSJeff Layton struct nfsd_file *file; 243878599c42SJ. Bruce Fields struct nfs4_stateowner *oo; 243978599c42SJ. Bruce Fields unsigned int access, deny; 244078599c42SJ. Bruce Fields 244178599c42SJ. Bruce Fields if (st->sc_type != NFS4_OPEN_STID && st->sc_type != NFS4_LOCK_STID) 244278599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 244378599c42SJ. Bruce Fields ols = openlockstateid(st); 244478599c42SJ. Bruce Fields oo = ols->st_stateowner; 244578599c42SJ. Bruce Fields nf = st->sc_file; 244678599c42SJ. Bruce Fields file = find_any_file(nf); 244778599c42SJ. Bruce Fields 2448ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2449ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2450ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: open, "); 245178599c42SJ. Bruce Fields 245278599c42SJ. Bruce Fields access = bmap_to_share_mode(ols->st_access_bmap); 245378599c42SJ. Bruce Fields deny = bmap_to_share_mode(ols->st_deny_bmap); 245478599c42SJ. Bruce Fields 2455c4b77edbSJ. Bruce Fields seq_printf(s, "access: %s%s, ", 245678599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_READ ? "r" : "-", 245778599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 2458c4b77edbSJ. Bruce Fields seq_printf(s, "deny: %s%s, ", 245978599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", 246078599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 246178599c42SJ. Bruce Fields 246278599c42SJ. Bruce Fields nfs4_show_superblock(s, file); 246378599c42SJ. Bruce Fields seq_printf(s, ", "); 2464580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2465580da465SAchilles Gaikwad seq_printf(s, ", "); 246678599c42SJ. Bruce Fields nfs4_show_owner(s, oo); 246778599c42SJ. Bruce Fields seq_printf(s, " }\n"); 2468fd4f83fdSJeff Layton nfsd_file_put(file); 246978599c42SJ. Bruce Fields 247078599c42SJ. Bruce Fields return 0; 247178599c42SJ. Bruce Fields } 247278599c42SJ. Bruce Fields 247316d36e09SJ. Bruce Fields static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) 247416d36e09SJ. Bruce Fields { 247516d36e09SJ. Bruce Fields struct nfs4_ol_stateid *ols; 247616d36e09SJ. Bruce Fields struct nfs4_file *nf; 2477fd4f83fdSJeff Layton struct nfsd_file *file; 247816d36e09SJ. Bruce Fields struct nfs4_stateowner *oo; 247916d36e09SJ. Bruce Fields 248016d36e09SJ. Bruce Fields ols = openlockstateid(st); 248116d36e09SJ. Bruce Fields oo = ols->st_stateowner; 248216d36e09SJ. Bruce Fields nf = st->sc_file; 248316d36e09SJ. Bruce Fields file = find_any_file(nf); 248416d36e09SJ. Bruce Fields 2485ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2486ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2487ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: lock, "); 248816d36e09SJ. Bruce Fields 248916d36e09SJ. Bruce Fields /* 249016d36e09SJ. Bruce Fields * Note: a lock stateid isn't really the same thing as a lock, 249116d36e09SJ. Bruce Fields * it's the locking state held by one owner on a file, and there 249216d36e09SJ. Bruce Fields * may be multiple (or no) lock ranges associated with it. 249316d36e09SJ. Bruce Fields * (Same for the matter is true of open stateids.) 249416d36e09SJ. Bruce Fields */ 249516d36e09SJ. Bruce Fields 249616d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 249716d36e09SJ. Bruce Fields /* XXX: open stateid? */ 249816d36e09SJ. Bruce Fields seq_printf(s, ", "); 2499580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2500580da465SAchilles Gaikwad seq_printf(s, ", "); 250116d36e09SJ. Bruce Fields nfs4_show_owner(s, oo); 250216d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2503fd4f83fdSJeff Layton nfsd_file_put(file); 250416d36e09SJ. Bruce Fields 250516d36e09SJ. Bruce Fields return 0; 250616d36e09SJ. Bruce Fields } 250716d36e09SJ. Bruce Fields 250816d36e09SJ. Bruce Fields static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) 250916d36e09SJ. Bruce Fields { 251016d36e09SJ. Bruce Fields struct nfs4_delegation *ds; 251116d36e09SJ. Bruce Fields struct nfs4_file *nf; 2512eb82dd39SJeff Layton struct nfsd_file *file; 251316d36e09SJ. Bruce Fields 251416d36e09SJ. Bruce Fields ds = delegstateid(st); 251516d36e09SJ. Bruce Fields nf = st->sc_file; 251616d36e09SJ. Bruce Fields file = nf->fi_deleg_file; 251716d36e09SJ. Bruce Fields 2518ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2519ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2520ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: deleg, "); 252116d36e09SJ. Bruce Fields 252216d36e09SJ. Bruce Fields /* Kinda dead code as long as we only support read delegs: */ 252316d36e09SJ. Bruce Fields seq_printf(s, "access: %s, ", 252416d36e09SJ. Bruce Fields ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); 252516d36e09SJ. Bruce Fields 252616d36e09SJ. Bruce Fields /* XXX: lease time, whether it's being recalled. */ 252716d36e09SJ. Bruce Fields 252816d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 2529580da465SAchilles Gaikwad seq_printf(s, ", "); 2530580da465SAchilles Gaikwad nfs4_show_fname(s, file); 253116d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 253216d36e09SJ. Bruce Fields 253316d36e09SJ. Bruce Fields return 0; 253416d36e09SJ. Bruce Fields } 253516d36e09SJ. Bruce Fields 25360c4b62b0SJ. Bruce Fields static int nfs4_show_layout(struct seq_file *s, struct nfs4_stid *st) 25370c4b62b0SJ. Bruce Fields { 25380c4b62b0SJ. Bruce Fields struct nfs4_layout_stateid *ls; 2539eb82dd39SJeff Layton struct nfsd_file *file; 25400c4b62b0SJ. Bruce Fields 25410c4b62b0SJ. Bruce Fields ls = container_of(st, struct nfs4_layout_stateid, ls_stid); 25420c4b62b0SJ. Bruce Fields file = ls->ls_file; 25430c4b62b0SJ. Bruce Fields 2544ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2545ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2546ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: layout, "); 25470c4b62b0SJ. Bruce Fields 25480c4b62b0SJ. Bruce Fields /* XXX: What else would be useful? */ 25490c4b62b0SJ. Bruce Fields 25500c4b62b0SJ. Bruce Fields nfs4_show_superblock(s, file); 2551580da465SAchilles Gaikwad seq_printf(s, ", "); 2552580da465SAchilles Gaikwad nfs4_show_fname(s, file); 25530c4b62b0SJ. Bruce Fields seq_printf(s, " }\n"); 25540c4b62b0SJ. Bruce Fields 25550c4b62b0SJ. Bruce Fields return 0; 25560c4b62b0SJ. Bruce Fields } 25570c4b62b0SJ. Bruce Fields 255878599c42SJ. Bruce Fields static int states_show(struct seq_file *s, void *v) 255978599c42SJ. Bruce Fields { 256078599c42SJ. Bruce Fields struct nfs4_stid *st = v; 256178599c42SJ. Bruce Fields 256278599c42SJ. Bruce Fields switch (st->sc_type) { 256378599c42SJ. Bruce Fields case NFS4_OPEN_STID: 256478599c42SJ. Bruce Fields return nfs4_show_open(s, st); 256516d36e09SJ. Bruce Fields case NFS4_LOCK_STID: 256616d36e09SJ. Bruce Fields return nfs4_show_lock(s, st); 256716d36e09SJ. Bruce Fields case NFS4_DELEG_STID: 256816d36e09SJ. Bruce Fields return nfs4_show_deleg(s, st); 25690c4b62b0SJ. Bruce Fields case NFS4_LAYOUT_STID: 25700c4b62b0SJ. Bruce Fields return nfs4_show_layout(s, st); 257178599c42SJ. Bruce Fields default: 257278599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 257378599c42SJ. Bruce Fields } 257416d36e09SJ. Bruce Fields /* XXX: copy stateids? */ 257578599c42SJ. Bruce Fields } 257678599c42SJ. Bruce Fields 257778599c42SJ. Bruce Fields static struct seq_operations states_seq_ops = { 257878599c42SJ. Bruce Fields .start = states_start, 257978599c42SJ. Bruce Fields .next = states_next, 258078599c42SJ. Bruce Fields .stop = states_stop, 258178599c42SJ. Bruce Fields .show = states_show 258278599c42SJ. Bruce Fields }; 258378599c42SJ. Bruce Fields 258478599c42SJ. Bruce Fields static int client_states_open(struct inode *inode, struct file *file) 258578599c42SJ. Bruce Fields { 258678599c42SJ. Bruce Fields struct seq_file *s; 258778599c42SJ. Bruce Fields struct nfs4_client *clp; 258878599c42SJ. Bruce Fields int ret; 258978599c42SJ. Bruce Fields 2590a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2591a204f25eSJ. Bruce Fields if (!clp) 259278599c42SJ. Bruce Fields return -ENXIO; 259378599c42SJ. Bruce Fields 259478599c42SJ. Bruce Fields ret = seq_open(file, &states_seq_ops); 259578599c42SJ. Bruce Fields if (ret) 259678599c42SJ. Bruce Fields return ret; 259778599c42SJ. Bruce Fields s = file->private_data; 259878599c42SJ. Bruce Fields s->private = clp; 259978599c42SJ. Bruce Fields return 0; 260078599c42SJ. Bruce Fields } 260178599c42SJ. Bruce Fields 260278599c42SJ. Bruce Fields static int client_opens_release(struct inode *inode, struct file *file) 260378599c42SJ. Bruce Fields { 260478599c42SJ. Bruce Fields struct seq_file *m = file->private_data; 260578599c42SJ. Bruce Fields struct nfs4_client *clp = m->private; 260678599c42SJ. Bruce Fields 260778599c42SJ. Bruce Fields /* XXX: alternatively, we could get/drop in seq start/stop */ 260878599c42SJ. Bruce Fields drop_client(clp); 260978599c42SJ. Bruce Fields return 0; 261078599c42SJ. Bruce Fields } 261178599c42SJ. Bruce Fields 261278599c42SJ. Bruce Fields static const struct file_operations client_states_fops = { 261378599c42SJ. Bruce Fields .open = client_states_open, 261478599c42SJ. Bruce Fields .read = seq_read, 261578599c42SJ. Bruce Fields .llseek = seq_lseek, 261678599c42SJ. Bruce Fields .release = client_opens_release, 261778599c42SJ. Bruce Fields }; 261878599c42SJ. Bruce Fields 261989c905beSJ. Bruce Fields /* 262089c905beSJ. Bruce Fields * Normally we refuse to destroy clients that are in use, but here the 262189c905beSJ. Bruce Fields * administrator is telling us to just do it. We also want to wait 262289c905beSJ. Bruce Fields * so the caller has a guarantee that the client's locks are gone by 262389c905beSJ. Bruce Fields * the time the write returns: 262489c905beSJ. Bruce Fields */ 2625297e57a2SYueHaibing static void force_expire_client(struct nfs4_client *clp) 262689c905beSJ. Bruce Fields { 262789c905beSJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 262889c905beSJ. Bruce Fields bool already_expired; 262989c905beSJ. Bruce Fields 263089c905beSJ. Bruce Fields spin_lock(&clp->cl_lock); 263189c905beSJ. Bruce Fields clp->cl_time = 0; 263289c905beSJ. Bruce Fields spin_unlock(&clp->cl_lock); 263389c905beSJ. Bruce Fields 263489c905beSJ. Bruce Fields wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0); 263589c905beSJ. Bruce Fields spin_lock(&nn->client_lock); 263689c905beSJ. Bruce Fields already_expired = list_empty(&clp->cl_lru); 263789c905beSJ. Bruce Fields if (!already_expired) 263889c905beSJ. Bruce Fields unhash_client_locked(clp); 263989c905beSJ. Bruce Fields spin_unlock(&nn->client_lock); 264089c905beSJ. Bruce Fields 264189c905beSJ. Bruce Fields if (!already_expired) 264289c905beSJ. Bruce Fields expire_client(clp); 264389c905beSJ. Bruce Fields else 264489c905beSJ. Bruce Fields wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL); 264589c905beSJ. Bruce Fields } 264689c905beSJ. Bruce Fields 264789c905beSJ. Bruce Fields static ssize_t client_ctl_write(struct file *file, const char __user *buf, 264889c905beSJ. Bruce Fields size_t size, loff_t *pos) 264989c905beSJ. Bruce Fields { 265089c905beSJ. Bruce Fields char *data; 265189c905beSJ. Bruce Fields struct nfs4_client *clp; 265289c905beSJ. Bruce Fields 265389c905beSJ. Bruce Fields data = simple_transaction_get(file, buf, size); 265489c905beSJ. Bruce Fields if (IS_ERR(data)) 265589c905beSJ. Bruce Fields return PTR_ERR(data); 265689c905beSJ. Bruce Fields if (size != 7 || 0 != memcmp(data, "expire\n", 7)) 265789c905beSJ. Bruce Fields return -EINVAL; 265889c905beSJ. Bruce Fields clp = get_nfsdfs_clp(file_inode(file)); 265989c905beSJ. Bruce Fields if (!clp) 266089c905beSJ. Bruce Fields return -ENXIO; 266189c905beSJ. Bruce Fields force_expire_client(clp); 266289c905beSJ. Bruce Fields drop_client(clp); 266389c905beSJ. Bruce Fields return 7; 266489c905beSJ. Bruce Fields } 266589c905beSJ. Bruce Fields 266689c905beSJ. Bruce Fields static const struct file_operations client_ctl_fops = { 266789c905beSJ. Bruce Fields .write = client_ctl_write, 266889c905beSJ. Bruce Fields .release = simple_transaction_release, 266989c905beSJ. Bruce Fields }; 267089c905beSJ. Bruce Fields 267197ad4031SJ. Bruce Fields static const struct tree_descr client_files[] = { 267297ad4031SJ. Bruce Fields [0] = {"info", &client_info_fops, S_IRUSR}, 267378599c42SJ. Bruce Fields [1] = {"states", &client_states_fops, S_IRUSR}, 26746cbfad5fSPetr Vorel [2] = {"ctl", &client_ctl_fops, S_IWUSR}, 267578599c42SJ. Bruce Fields [3] = {""}, 267697ad4031SJ. Bruce Fields }; 267797ad4031SJ. Bruce Fields 26782216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2679b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2680b09333c4SRicardo Labiaga { 2681b09333c4SRicardo Labiaga struct nfs4_client *clp; 2682b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 268303a4e1f6SJ. Bruce Fields int ret; 2684c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2685e8a79fb1SJ. Bruce Fields struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2686b09333c4SRicardo Labiaga 2687b09333c4SRicardo Labiaga clp = alloc_client(name); 2688b09333c4SRicardo Labiaga if (clp == NULL) 2689b09333c4SRicardo Labiaga return NULL; 2690b09333c4SRicardo Labiaga 269103a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 269203a4e1f6SJ. Bruce Fields if (ret) { 2693b09333c4SRicardo Labiaga free_client(clp); 2694b09333c4SRicardo Labiaga return NULL; 2695b09333c4SRicardo Labiaga } 2696e8a79fb1SJ. Bruce Fields gen_clid(clp, nn); 2697e8a79fb1SJ. Bruce Fields kref_init(&clp->cl_nfsdfs.cl_ref); 26980162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 269920b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 2700b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2701b09333c4SRicardo Labiaga copy_verf(clp, verf); 27023bade247SJ. Bruce Fields memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); 2703edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2704c212cecfSStanislav Kinsbursky clp->net = net; 2705e8a79fb1SJ. Bruce Fields clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs, 270697ad4031SJ. Bruce Fields clp->cl_clientid.cl_id - nn->clientid_base, 270797ad4031SJ. Bruce Fields client_files); 2708e8a79fb1SJ. Bruce Fields if (!clp->cl_nfsd_dentry) { 2709e8a79fb1SJ. Bruce Fields free_client(clp); 2710e8a79fb1SJ. Bruce Fields return NULL; 2711e8a79fb1SJ. Bruce Fields } 2712b09333c4SRicardo Labiaga return clp; 2713b09333c4SRicardo Labiaga } 2714b09333c4SRicardo Labiaga 2715fd39ca9aSNeilBrown static void 2716ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2717ac55fdc4SJeff Layton { 2718ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2719ac55fdc4SJeff Layton struct nfs4_client *clp; 2720ac55fdc4SJeff Layton 2721ac55fdc4SJeff Layton while (*new) { 2722ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2723ac55fdc4SJeff Layton parent = *new; 2724ac55fdc4SJeff Layton 2725ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2726ac55fdc4SJeff Layton new = &((*new)->rb_left); 2727ac55fdc4SJeff Layton else 2728ac55fdc4SJeff Layton new = &((*new)->rb_right); 2729ac55fdc4SJeff Layton } 2730ac55fdc4SJeff Layton 2731ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2732ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2733ac55fdc4SJeff Layton } 2734ac55fdc4SJeff Layton 2735ac55fdc4SJeff Layton static struct nfs4_client * 2736ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2737ac55fdc4SJeff Layton { 2738ef17af2aSRasmus Villemoes int cmp; 2739ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2740ac55fdc4SJeff Layton struct nfs4_client *clp; 2741ac55fdc4SJeff Layton 2742ac55fdc4SJeff Layton while (node) { 2743ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2744ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2745ac55fdc4SJeff Layton if (cmp > 0) 2746ac55fdc4SJeff Layton node = node->rb_left; 2747ac55fdc4SJeff Layton else if (cmp < 0) 2748ac55fdc4SJeff Layton node = node->rb_right; 2749ac55fdc4SJeff Layton else 2750ac55fdc4SJeff Layton return clp; 2751ac55fdc4SJeff Layton } 2752ac55fdc4SJeff Layton return NULL; 2753ac55fdc4SJeff Layton } 2754ac55fdc4SJeff Layton 2755ac55fdc4SJeff Layton static void 2756ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 27571da177e4SLinus Torvalds { 27581da177e4SLinus Torvalds unsigned int idhashval; 27590a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 27601da177e4SLinus Torvalds 27610a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 27620a880a28STrond Myklebust 2763ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2764a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 27651da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 27660a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 27673dbacee6STrond Myklebust renew_client_locked(clp); 27681da177e4SLinus Torvalds } 27691da177e4SLinus Torvalds 2770fd39ca9aSNeilBrown static void 27711da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 27721da177e4SLinus Torvalds { 27731da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 27748daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 27751da177e4SLinus Torvalds 27760a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 27770a880a28STrond Myklebust 27781da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 27798daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2780a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2781382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2782ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 27833dbacee6STrond Myklebust renew_client_locked(clp); 27841da177e4SLinus Torvalds } 27851da177e4SLinus Torvalds 27861da177e4SLinus Torvalds static struct nfs4_client * 2787bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 27881da177e4SLinus Torvalds { 27891da177e4SLinus Torvalds struct nfs4_client *clp; 27901da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 27911da177e4SLinus Torvalds 2792bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2793a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2794d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2795d15c077eSJ. Bruce Fields return NULL; 27963dbacee6STrond Myklebust renew_client_locked(clp); 27971da177e4SLinus Torvalds return clp; 27981da177e4SLinus Torvalds } 2799a50d2ad1SJ. Bruce Fields } 28001da177e4SLinus Torvalds return NULL; 28011da177e4SLinus Torvalds } 28021da177e4SLinus Torvalds 28031da177e4SLinus Torvalds static struct nfs4_client * 2804bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2805bfa85e83SJ. Bruce Fields { 2806bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2807bfa85e83SJ. Bruce Fields 28080a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2809bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2810bfa85e83SJ. Bruce Fields } 2811bfa85e83SJ. Bruce Fields 2812bfa85e83SJ. Bruce Fields static struct nfs4_client * 28130a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 28141da177e4SLinus Torvalds { 2815bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 28161da177e4SLinus Torvalds 28170a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2818bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 28191da177e4SLinus Torvalds } 28201da177e4SLinus Torvalds 28216e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2822a1bcecd2SAndy Adamson { 28236e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2824a1bcecd2SAndy Adamson } 2825a1bcecd2SAndy Adamson 282628ce6054SNeilBrown static struct nfs4_client * 2827382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 282828ce6054SNeilBrown { 28290a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2830382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 283128ce6054SNeilBrown } 283228ce6054SNeilBrown 283328ce6054SNeilBrown static struct nfs4_client * 2834a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 283528ce6054SNeilBrown { 28360a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2837a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 283828ce6054SNeilBrown } 283928ce6054SNeilBrown 2840fd39ca9aSNeilBrown static void 28416f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 28421da177e4SLinus Torvalds { 284307263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 28446f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 28456f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 28467077ecbaSJeff Layton unsigned short expected_family; 28471da177e4SLinus Torvalds 28487077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 28497077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 28507077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 28517077ecbaSJeff Layton expected_family = AF_INET; 28527077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 28537077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 28547077ecbaSJeff Layton expected_family = AF_INET6; 28557077ecbaSJeff Layton else 28561da177e4SLinus Torvalds goto out_err; 28571da177e4SLinus Torvalds 2858c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2859aa9a4ec7SJeff Layton se->se_callback_addr_len, 286007263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 286107263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2862aa9a4ec7SJeff Layton 286307263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 28641da177e4SLinus Torvalds goto out_err; 2865aa9a4ec7SJeff Layton 286607263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 286707263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2868fbf4665fSJeff Layton 286907263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 287007263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2871849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 28721eace0d1SChuck Lever trace_nfsd_cb_args(clp, conn); 28731da177e4SLinus Torvalds return; 28741da177e4SLinus Torvalds out_err: 287507263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 287607263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 28771eace0d1SChuck Lever trace_nfsd_cb_nodelegs(clp); 28781da177e4SLinus Torvalds return; 28791da177e4SLinus Torvalds } 28801da177e4SLinus Torvalds 2881074fe897SAndy Adamson /* 2882067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2883074fe897SAndy Adamson */ 2884b607664eSTrond Myklebust static void 2885074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2886074fe897SAndy Adamson { 2887f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2888557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2889557ce264SAndy Adamson unsigned int base; 2890074fe897SAndy Adamson 2891557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2892074fe897SAndy Adamson 2893085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2894557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2895557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 289653da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 289753da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 2898bf864a31SAndy Adamson 2899085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 2900085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 2901bf864a31SAndy Adamson return; 2902bf864a31SAndy Adamson } 2903085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 2904085def3aSJ. Bruce Fields 2905f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2906f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2907f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2908d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 2909d3f03403SDan Carpenter __func__); 2910557ce264SAndy Adamson return; 2911074fe897SAndy Adamson } 2912074fe897SAndy Adamson 2913074fe897SAndy Adamson /* 2914abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2915abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2916abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2917abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2918abfabf8cSAndy Adamson * 2919074fe897SAndy Adamson */ 2920abfabf8cSAndy Adamson static __be32 2921abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2922abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2923074fe897SAndy Adamson { 2924abfabf8cSAndy Adamson struct nfsd4_op *op; 2925abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2926074fe897SAndy Adamson 2927abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2928abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2929abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2930abfabf8cSAndy Adamson 2931085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 2932085def3aSJ. Bruce Fields return op->status; 2933085def3aSJ. Bruce Fields if (args->opcnt == 1) { 2934085def3aSJ. Bruce Fields /* 2935085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 2936085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 2937085def3aSJ. Bruce Fields * original: 2938085def3aSJ. Bruce Fields */ 2939085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 2940085def3aSJ. Bruce Fields } else { 2941abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2942abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2943abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2944074fe897SAndy Adamson } 2945abfabf8cSAndy Adamson return op->status; 2946074fe897SAndy Adamson } 2947074fe897SAndy Adamson 2948074fe897SAndy Adamson /* 2949557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2950557ce264SAndy Adamson * session values. 2951074fe897SAndy Adamson */ 29523ca2eb98SJ. Bruce Fields static __be32 2953bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2954bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2955074fe897SAndy Adamson { 2956557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2957f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2958f5236013SJ. Bruce Fields __be32 *p; 2959074fe897SAndy Adamson __be32 status; 2960074fe897SAndy Adamson 2961557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2962074fe897SAndy Adamson 2963abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 29640da7b19cSJ. Bruce Fields if (status) 2965abfabf8cSAndy Adamson return status; 2966074fe897SAndy Adamson 2967f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2968f5236013SJ. Bruce Fields if (!p) { 2969f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2970f5236013SJ. Bruce Fields return nfserr_serverfault; 2971f5236013SJ. Bruce Fields } 2972f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2973f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2974074fe897SAndy Adamson 2975557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2976f5236013SJ. Bruce Fields return slot->sl_status; 2977074fe897SAndy Adamson } 2978074fe897SAndy Adamson 29790733d213SAndy Adamson /* 29800733d213SAndy Adamson * Set the exchange_id flags returned by the server. 29810733d213SAndy Adamson */ 29820733d213SAndy Adamson static void 29830733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 29840733d213SAndy Adamson { 29859cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 29869cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 29879cf514ccSChristoph Hellwig #else 29880733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 29899cf514ccSChristoph Hellwig #endif 29900733d213SAndy Adamson 29910733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 29920733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 29930733d213SAndy Adamson 29940733d213SAndy Adamson /* set the wire flags to return to client. */ 29950733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 29960733d213SAndy Adamson } 29970733d213SAndy Adamson 29984eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 29994eaea134SJ. Bruce Fields { 30004eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 30014eaea134SJ. Bruce Fields 30024eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 30034eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 30044eaea134SJ. Bruce Fields return true; 30054eaea134SJ. Bruce Fields } 30064eaea134SJ. Bruce Fields return false; 30074eaea134SJ. Bruce Fields } 30084eaea134SJ. Bruce Fields 3009631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 3010631fc9eaSJ. Bruce Fields { 30114eaea134SJ. Bruce Fields return client_has_openowners(clp) 301247e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 301347e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 301447e970beSKinglong Mee #endif 30156eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 3016e0639dc5SOlga Kornievskaia || !list_empty(&clp->cl_sessions) 3017e0639dc5SOlga Kornievskaia || !list_empty(&clp->async_copies); 3018631fc9eaSJ. Bruce Fields } 3019631fc9eaSJ. Bruce Fields 302079123444SJ. Bruce Fields static __be32 copy_impl_id(struct nfs4_client *clp, 302179123444SJ. Bruce Fields struct nfsd4_exchange_id *exid) 302279123444SJ. Bruce Fields { 302379123444SJ. Bruce Fields if (!exid->nii_domain.data) 302479123444SJ. Bruce Fields return 0; 302579123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_domain, &exid->nii_domain, GFP_KERNEL); 302679123444SJ. Bruce Fields if (!clp->cl_nii_domain.data) 302779123444SJ. Bruce Fields return nfserr_jukebox; 302879123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_name, &exid->nii_name, GFP_KERNEL); 302979123444SJ. Bruce Fields if (!clp->cl_nii_name.data) 303079123444SJ. Bruce Fields return nfserr_jukebox; 3031e29f4703SArnd Bergmann clp->cl_nii_time = exid->nii_time; 303279123444SJ. Bruce Fields return 0; 303379123444SJ. Bruce Fields } 303479123444SJ. Bruce Fields 3035b37ad28bSAl Viro __be32 3036eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3037eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3038069b6ad4SAndy Adamson { 3039eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 30403dbacee6STrond Myklebust struct nfs4_client *conf, *new; 30413dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 304257b7b43bSJ. Bruce Fields __be32 status; 3043363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 30440733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 3045363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 304683e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 3047c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 30480733d213SAndy Adamson 3049363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 30500733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 3051363168b4SJeff Layton "ip_addr=%s flags %x, spa_how %d\n", 30520733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 3053363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 30540733d213SAndy Adamson 3055a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 30560733d213SAndy Adamson return nfserr_inval; 30570733d213SAndy Adamson 305850c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 305950c7b948SJ. Bruce Fields if (new == NULL) 306050c7b948SJ. Bruce Fields return nfserr_jukebox; 306179123444SJ. Bruce Fields status = copy_impl_id(new, exid); 306279123444SJ. Bruce Fields if (status) 306379123444SJ. Bruce Fields goto out_nolock; 306450c7b948SJ. Bruce Fields 30650733d213SAndy Adamson switch (exid->spa_how) { 306657266a6eSJ. Bruce Fields case SP4_MACH_CRED: 3067ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 3068ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 3069ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 3070ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 3071ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 3072ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 3073ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 3074ed941643SAndrew Elble 3075ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 3076ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 3077ed941643SAndrew Elble 1 << (OP_LOCKU) | 3078ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 3079ed941643SAndrew Elble 3080ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 3081ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 3082ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 308350c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 308450c7b948SJ. Bruce Fields status = nfserr_inval; 308550c7b948SJ. Bruce Fields goto out_nolock; 308650c7b948SJ. Bruce Fields } 3087920dd9bbSJ. Bruce Fields /* 3088920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 3089920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 3090920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 3091920dd9bbSJ. Bruce Fields */ 3092414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 3093414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 3094920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 3095920dd9bbSJ. Bruce Fields goto out_nolock; 3096920dd9bbSJ. Bruce Fields } 309750c7b948SJ. Bruce Fields new->cl_mach_cred = true; 30980733d213SAndy Adamson case SP4_NONE: 30990733d213SAndy Adamson break; 3100063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 3101063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 31020a4c9265SGustavo A. R. Silva /* fall through */ 31030733d213SAndy Adamson case SP4_SSV: 31048edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 31058edf4b02SKinglong Mee goto out_nolock; 31060733d213SAndy Adamson } 31070733d213SAndy Adamson 31082dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 31093dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3110382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 31110733d213SAndy Adamson if (conf) { 311283e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 311383e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 311483e08fd4SJ. Bruce Fields 3115136e658dSJ. Bruce Fields if (update) { 3116136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 31172dbb269dSJ. Bruce Fields status = nfserr_inval; 3118e203d506SJ. Bruce Fields goto out; 3119e203d506SJ. Bruce Fields } 3120dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 312157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 312257266a6eSJ. Bruce Fields goto out; 312357266a6eSJ. Bruce Fields } 31242dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 31250733d213SAndy Adamson status = nfserr_perm; 31260733d213SAndy Adamson goto out; 31270733d213SAndy Adamson } 31282dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 31290733d213SAndy Adamson status = nfserr_not_same; 31300733d213SAndy Adamson goto out; 31310733d213SAndy Adamson } 3132136e658dSJ. Bruce Fields /* case 6 */ 31330733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 31340733d213SAndy Adamson goto out_copy; 31356ddbbbfeSMike Sager } 3136136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 3137631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 3138136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 3139136e658dSJ. Bruce Fields goto out; 3140136e658dSJ. Bruce Fields } 3141b9831b59SJ. Bruce Fields goto out_new; 3142631fc9eaSJ. Bruce Fields } 3143136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 31440f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 3145136e658dSJ. Bruce Fields goto out_copy; 3146136e658dSJ. Bruce Fields } 31472dbb269dSJ. Bruce Fields /* case 5, client reboot */ 31483dbacee6STrond Myklebust conf = NULL; 31490733d213SAndy Adamson goto out_new; 31500733d213SAndy Adamson } 31516ddbbbfeSMike Sager 31522dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 31530733d213SAndy Adamson status = nfserr_noent; 31540733d213SAndy Adamson goto out; 31550733d213SAndy Adamson } 31560733d213SAndy Adamson 3157a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 31582dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 31593dbacee6STrond Myklebust unhash_client_locked(unconf); 31600733d213SAndy Adamson 31612dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 31620733d213SAndy Adamson out_new: 3163fd699b8aSJeff Layton if (conf) { 3164fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3165fd699b8aSJeff Layton if (status) 3166fd699b8aSJeff Layton goto out; 3167fd699b8aSJeff Layton } 31684f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 3169ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 3170ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 31710733d213SAndy Adamson 3172ac55fdc4SJeff Layton add_to_unconfirmed(new); 31733dbacee6STrond Myklebust swap(new, conf); 31740733d213SAndy Adamson out_copy: 31755cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 31765cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 31770733d213SAndy Adamson 31785cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 31795cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 31800733d213SAndy Adamson 31810733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 31825cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 31830733d213SAndy Adamson status = nfs_ok; 31840733d213SAndy Adamson 31850733d213SAndy Adamson out: 31863dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 318750c7b948SJ. Bruce Fields out_nolock: 31885cc40fd7STrond Myklebust if (new) 31893dbacee6STrond Myklebust expire_client(new); 31903dbacee6STrond Myklebust if (unconf) 31913dbacee6STrond Myklebust expire_client(unconf); 31920733d213SAndy Adamson return status; 3193069b6ad4SAndy Adamson } 3194069b6ad4SAndy Adamson 319557b7b43bSJ. Bruce Fields static __be32 319688e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 3197b85d4c01SBenny Halevy { 319888e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 319988e588d5SAndy Adamson slot_seqid); 3200b85d4c01SBenny Halevy 3201b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 320288e588d5SAndy Adamson if (slot_inuse) { 320388e588d5SAndy Adamson if (seqid == slot_seqid) 3204b85d4c01SBenny Halevy return nfserr_jukebox; 3205b85d4c01SBenny Halevy else 3206b85d4c01SBenny Halevy return nfserr_seq_misordered; 3207b85d4c01SBenny Halevy } 3208f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 320988e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 3210b85d4c01SBenny Halevy return nfs_ok; 321188e588d5SAndy Adamson if (seqid == slot_seqid) 3212b85d4c01SBenny Halevy return nfserr_replay_cache; 3213b85d4c01SBenny Halevy return nfserr_seq_misordered; 3214b85d4c01SBenny Halevy } 3215b85d4c01SBenny Halevy 321649557cc7SAndy Adamson /* 321749557cc7SAndy Adamson * Cache the create session result into the create session single DRC 321849557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 321949557cc7SAndy Adamson * Do this for solo or embedded create session operations. 322049557cc7SAndy Adamson */ 322149557cc7SAndy Adamson static void 322249557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 322357b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 322449557cc7SAndy Adamson { 322549557cc7SAndy Adamson slot->sl_status = nfserr; 322649557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 322749557cc7SAndy Adamson } 322849557cc7SAndy Adamson 322949557cc7SAndy Adamson static __be32 323049557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 323149557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 323249557cc7SAndy Adamson { 323349557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 323449557cc7SAndy Adamson return slot->sl_status; 323549557cc7SAndy Adamson } 323649557cc7SAndy Adamson 32371b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 32381b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 32391b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 32401b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 32411b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 32421b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 32431b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 32441b74c25bSMi Jinlong 32451b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 32461b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 32471b74c25bSMi Jinlong 1 + /* status */ \ 32481b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 32491b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 32501b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 32511b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 32521b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 32531b74c25bSMi Jinlong 325455c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 32551b74c25bSMi Jinlong { 325655c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 325755c760cfSJ. Bruce Fields 3258373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 3259373cd409SJ. Bruce Fields return nfserr_toosmall; 3260373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 3261373cd409SJ. Bruce Fields return nfserr_toosmall; 326255c760cfSJ. Bruce Fields ca->headerpadsz = 0; 326355c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 326455c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 326555c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 326655c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 326755c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 326855c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 326955c760cfSJ. Bruce Fields /* 327055c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 327155c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 327255c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 327355c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 327455c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 327555c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 32767f49fd5dSNeilBrown * Note that we always allow at least one slot, because our 32777f49fd5dSNeilBrown * accounting is soft and provides no guarantees either way. 327855c760cfSJ. Bruce Fields */ 32792030ca56SNeilBrown ca->maxreqs = nfsd4_get_drc_mem(ca, nn); 328055c760cfSJ. Bruce Fields 3281373cd409SJ. Bruce Fields return nfs_ok; 32821b74c25bSMi Jinlong } 32831b74c25bSMi Jinlong 32844500632fSChuck Lever /* 32854500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 32864500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 32874500632fSChuck Lever */ 32884500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 32894500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 32904500632fSChuck Lever 32914500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 32924500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 32934500632fSChuck Lever 32948a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 32954500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 32968a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 32974500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 32984500632fSChuck Lever sizeof(__be32)) 32998a891633SKinglong Mee 330006b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 330106b332a5SJ. Bruce Fields { 330206b332a5SJ. Bruce Fields ca->headerpadsz = 0; 330306b332a5SJ. Bruce Fields 33048a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 330506b332a5SJ. Bruce Fields return nfserr_toosmall; 33068a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 330706b332a5SJ. Bruce Fields return nfserr_toosmall; 330806b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 330906b332a5SJ. Bruce Fields if (ca->maxops < 2) 331006b332a5SJ. Bruce Fields return nfserr_toosmall; 331106b332a5SJ. Bruce Fields 331206b332a5SJ. Bruce Fields return nfs_ok; 3313069b6ad4SAndy Adamson } 3314069b6ad4SAndy Adamson 3315b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 3316b78724b7SJ. Bruce Fields { 3317b78724b7SJ. Bruce Fields switch (cbs->flavor) { 3318b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 3319b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 3320b78724b7SJ. Bruce Fields return nfs_ok; 3321b78724b7SJ. Bruce Fields default: 3322b78724b7SJ. Bruce Fields /* 3323b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 3324b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 3325b78724b7SJ. Bruce Fields * GSS. 3326b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 3327b78724b7SJ. Bruce Fields * client might think it can already handle: 3328b78724b7SJ. Bruce Fields */ 3329b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 3330b78724b7SJ. Bruce Fields } 3331b78724b7SJ. Bruce Fields } 3332b78724b7SJ. Bruce Fields 3333069b6ad4SAndy Adamson __be32 3334069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 3335eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 3336069b6ad4SAndy Adamson { 3337eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 3338363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 3339ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 3340d20c11d8SJeff Layton struct nfs4_client *old = NULL; 3341ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 334281f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 334349557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 334457b7b43bSJ. Bruce Fields __be32 status = 0; 33458daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3346ec6b5d7bSAndy Adamson 3347a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 3348a62573dcSMi Jinlong return nfserr_inval; 3349b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 3350b78724b7SJ. Bruce Fields if (status) 3351b78724b7SJ. Bruce Fields return status; 335255c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 3353373cd409SJ. Bruce Fields if (status) 3354373cd409SJ. Bruce Fields return status; 335506b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 335606b332a5SJ. Bruce Fields if (status) 3357f403e450SKinglong Mee goto out_release_drc_mem; 335881f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 335960810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 336055c760cfSJ. Bruce Fields if (!new) 336155c760cfSJ. Bruce Fields goto out_release_drc_mem; 336281f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 336381f0b2a4SJ. Bruce Fields if (!conn) 336481f0b2a4SJ. Bruce Fields goto out_free_session; 3365a62573dcSMi Jinlong 3366d20c11d8SJeff Layton spin_lock(&nn->client_lock); 33670a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 33688daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 336978389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3370ec6b5d7bSAndy Adamson 3371ec6b5d7bSAndy Adamson if (conf) { 337257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3373dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 337457266a6eSJ. Bruce Fields goto out_free_conn; 337549557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 337649557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 3377f5e22bb6SKinglong Mee if (status) { 3378f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 337949557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 338081f0b2a4SJ. Bruce Fields goto out_free_conn; 3381ec6b5d7bSAndy Adamson } 3382ec6b5d7bSAndy Adamson } else if (unconf) { 3383ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 3384363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 3385ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 338681f0b2a4SJ. Bruce Fields goto out_free_conn; 3387ec6b5d7bSAndy Adamson } 338857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3389dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 339057266a6eSJ. Bruce Fields goto out_free_conn; 339149557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 339249557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 339338eb76a5SAndy Adamson if (status) { 339438eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 3395ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 339681f0b2a4SJ. Bruce Fields goto out_free_conn; 3397ec6b5d7bSAndy Adamson } 3398382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3399221a6876SJ. Bruce Fields if (old) { 3400d20c11d8SJeff Layton status = mark_client_expired_locked(old); 34017abea1e8SJeff Layton if (status) { 34027abea1e8SJeff Layton old = NULL; 3403221a6876SJ. Bruce Fields goto out_free_conn; 3404221a6876SJ. Bruce Fields } 34057abea1e8SJeff Layton } 34068f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 3407ec6b5d7bSAndy Adamson conf = unconf; 3408ec6b5d7bSAndy Adamson } else { 3409ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 341081f0b2a4SJ. Bruce Fields goto out_free_conn; 3411ec6b5d7bSAndy Adamson } 341281f0b2a4SJ. Bruce Fields status = nfs_ok; 34134ce85c8cSChuck Lever /* Persistent sessions are not supported */ 3414408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 34154ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 3416408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 3417408b79bcSJ. Bruce Fields 341881f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 3419d20c11d8SJeff Layton nfsd4_get_session_locked(new); 342081f0b2a4SJ. Bruce Fields 3421ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 3422ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 342386c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 342449557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 3425ec6b5d7bSAndy Adamson 3426d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 342749557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 3428d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3429d20c11d8SJeff Layton /* init connection and backchannel */ 3430d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 3431d20c11d8SJeff Layton nfsd4_put_session(new); 3432d20c11d8SJeff Layton if (old) 3433d20c11d8SJeff Layton expire_client(old); 3434ec6b5d7bSAndy Adamson return status; 343581f0b2a4SJ. Bruce Fields out_free_conn: 3436d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 343781f0b2a4SJ. Bruce Fields free_conn(conn); 3438d20c11d8SJeff Layton if (old) 3439d20c11d8SJeff Layton expire_client(old); 344081f0b2a4SJ. Bruce Fields out_free_session: 344181f0b2a4SJ. Bruce Fields __free_session(new); 344255c760cfSJ. Bruce Fields out_release_drc_mem: 344355c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 34441ca50792SJ. Bruce Fields return status; 3445069b6ad4SAndy Adamson } 3446069b6ad4SAndy Adamson 34471d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 34481d1bc8f2SJ. Bruce Fields { 34491d1bc8f2SJ. Bruce Fields switch (*dir) { 34501d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 34511d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 34521d1bc8f2SJ. Bruce Fields return nfs_ok; 34531d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 34541d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 34551d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 34561d1bc8f2SJ. Bruce Fields return nfs_ok; 3457fc5fc5d7Szhengbin } 34581d1bc8f2SJ. Bruce Fields return nfserr_inval; 34591d1bc8f2SJ. Bruce Fields } 34601d1bc8f2SJ. Bruce Fields 3461eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 3462eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3463eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3464cb73a9f4SJ. Bruce Fields { 3465eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 3466cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 3467c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3468b78724b7SJ. Bruce Fields __be32 status; 3469cb73a9f4SJ. Bruce Fields 3470b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 3471b78724b7SJ. Bruce Fields if (status) 3472b78724b7SJ. Bruce Fields return status; 3473c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3474cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 3475cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 3476c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3477cb73a9f4SJ. Bruce Fields 3478cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 3479cb73a9f4SJ. Bruce Fields 3480cb73a9f4SJ. Bruce Fields return nfs_ok; 3481cb73a9f4SJ. Bruce Fields } 3482cb73a9f4SJ. Bruce Fields 3483c2d715a1SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3484c2d715a1SJ. Bruce Fields { 3485c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3486c2d715a1SJ. Bruce Fields 3487c2d715a1SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3488c2d715a1SJ. Bruce Fields if (c->cn_xprt == xpt) { 3489c2d715a1SJ. Bruce Fields return c; 3490c2d715a1SJ. Bruce Fields } 3491c2d715a1SJ. Bruce Fields } 3492c2d715a1SJ. Bruce Fields return NULL; 3493c2d715a1SJ. Bruce Fields } 3494c2d715a1SJ. Bruce Fields 3495c2d715a1SJ. Bruce Fields static __be32 nfsd4_match_existing_connection(struct svc_rqst *rqst, 3496c2d715a1SJ. Bruce Fields struct nfsd4_session *session, u32 req) 3497c2d715a1SJ. Bruce Fields { 3498c2d715a1SJ. Bruce Fields struct nfs4_client *clp = session->se_client; 3499c2d715a1SJ. Bruce Fields struct svc_xprt *xpt = rqst->rq_xprt; 3500c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3501c2d715a1SJ. Bruce Fields __be32 status; 3502c2d715a1SJ. Bruce Fields 3503c2d715a1SJ. Bruce Fields /* Following the last paragraph of RFC 5661 Section 18.34.3: */ 3504c2d715a1SJ. Bruce Fields spin_lock(&clp->cl_lock); 3505c2d715a1SJ. Bruce Fields c = __nfsd4_find_conn(xpt, session); 3506c2d715a1SJ. Bruce Fields if (!c) 3507c2d715a1SJ. Bruce Fields status = nfserr_noent; 3508c2d715a1SJ. Bruce Fields else if (req == c->cn_flags) 3509c2d715a1SJ. Bruce Fields status = nfs_ok; 3510c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_FORE_OR_BOTH && 3511c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_BACK) 3512c2d715a1SJ. Bruce Fields status = nfs_ok; 3513c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_BACK_OR_BOTH && 3514c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_FORE) 3515c2d715a1SJ. Bruce Fields status = nfs_ok; 3516c2d715a1SJ. Bruce Fields else 3517c2d715a1SJ. Bruce Fields status = nfserr_inval; 3518c2d715a1SJ. Bruce Fields spin_unlock(&clp->cl_lock); 3519c2d715a1SJ. Bruce Fields return status; 3520c2d715a1SJ. Bruce Fields } 3521c2d715a1SJ. Bruce Fields 35221d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 35231d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 3524eb69853dSChristoph Hellwig union nfsd4_op_u *u) 35251d1bc8f2SJ. Bruce Fields { 3526eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 35271d1bc8f2SJ. Bruce Fields __be32 status; 35283ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 35294f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 3530d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3531d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 35321d1bc8f2SJ. Bruce Fields 35331d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 35341d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 3535c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3536d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 3537c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 35384f6e6c17SJ. Bruce Fields if (!session) 3539d4e19e70STrond Myklebust goto out_no_session; 354057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3541dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 354257266a6eSJ. Bruce Fields goto out; 3543c2d715a1SJ. Bruce Fields status = nfsd4_match_existing_connection(rqstp, session, bcts->dir); 3544c2d715a1SJ. Bruce Fields if (status == nfs_ok || status == nfserr_inval) 3545c2d715a1SJ. Bruce Fields goto out; 35461d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 35473ba63671SJ. Bruce Fields if (status) 35484f6e6c17SJ. Bruce Fields goto out; 35493ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 35504f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 35513ba63671SJ. Bruce Fields if (!conn) 35524f6e6c17SJ. Bruce Fields goto out; 35534f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 35544f6e6c17SJ. Bruce Fields status = nfs_ok; 35554f6e6c17SJ. Bruce Fields out: 3556d4e19e70STrond Myklebust nfsd4_put_session(session); 3557d4e19e70STrond Myklebust out_no_session: 35584f6e6c17SJ. Bruce Fields return status; 35591d1bc8f2SJ. Bruce Fields } 35601d1bc8f2SJ. Bruce Fields 3561665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 35625d4cec2fSJ. Bruce Fields { 3563665d5072SJ. Bruce Fields if (!cstate->session) 356451d87bc2SFengguang Wu return false; 3565665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 35665d4cec2fSJ. Bruce Fields } 35675d4cec2fSJ. Bruce Fields 3568069b6ad4SAndy Adamson __be32 3569eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 3570eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3571069b6ad4SAndy Adamson { 3572ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 3573e10e0cfcSBenny Halevy struct nfsd4_session *ses; 3574abcdff09SJ. Bruce Fields __be32 status; 3575f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 3576d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 3577d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3578e10e0cfcSBenny Halevy 3579abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 3580ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 358157716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 3582abcdff09SJ. Bruce Fields goto out; 3583f0f51f5cSJ. Bruce Fields ref_held_by_me++; 358457716355SJ. Bruce Fields } 3585ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 3586c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3587ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 3588abcdff09SJ. Bruce Fields if (!ses) 3589abcdff09SJ. Bruce Fields goto out_client_lock; 359057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3591dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 3592d4e19e70STrond Myklebust goto out_put_session; 3593f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 359466b2b9b2SJ. Bruce Fields if (status) 3595f0f51f5cSJ. Bruce Fields goto out_put_session; 3596e10e0cfcSBenny Halevy unhash_session(ses); 3597c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3598e10e0cfcSBenny Halevy 359984f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 360019cf5c02SJ. Bruce Fields 3601c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3602e10e0cfcSBenny Halevy status = nfs_ok; 3603f0f51f5cSJ. Bruce Fields out_put_session: 3604d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3605abcdff09SJ. Bruce Fields out_client_lock: 3606abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3607e10e0cfcSBenny Halevy out: 3608e10e0cfcSBenny Halevy return status; 3609069b6ad4SAndy Adamson } 3610069b6ad4SAndy Adamson 361157266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3612328ead28SJ. Bruce Fields { 3613328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3614a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 361557266a6eSJ. Bruce Fields __be32 status = nfs_ok; 361621b75b01SJ. Bruce Fields int ret; 3617328ead28SJ. Bruce Fields 3618328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3619a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 362057266a6eSJ. Bruce Fields if (c) 362157266a6eSJ. Bruce Fields goto out_free; 362257266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 362357266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 362457266a6eSJ. Bruce Fields goto out_free; 3625328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3626328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 362721b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 362821b75b01SJ. Bruce Fields if (ret) 362921b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 363021b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 363157266a6eSJ. Bruce Fields return nfs_ok; 363257266a6eSJ. Bruce Fields out_free: 363357266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 363457266a6eSJ. Bruce Fields free_conn(new); 363557266a6eSJ. Bruce Fields return status; 3636328ead28SJ. Bruce Fields } 3637328ead28SJ. Bruce Fields 3638868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3639868b89c3SMi Jinlong { 3640868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3641868b89c3SMi Jinlong 3642868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3643868b89c3SMi Jinlong } 3644868b89c3SMi Jinlong 3645ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3646ae82a8d0SMi Jinlong struct nfsd4_session *session) 3647ae82a8d0SMi Jinlong { 3648ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3649ae82a8d0SMi Jinlong 3650ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3651ae82a8d0SMi Jinlong } 3652ae82a8d0SMi Jinlong 365353da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 365453da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 365553da6a53SJ. Bruce Fields { 365653da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 365753da6a53SJ. Bruce Fields 365853da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 365953da6a53SJ. Bruce Fields (bool)seq->cachethis) 366053da6a53SJ. Bruce Fields return false; 366153da6a53SJ. Bruce Fields /* 36626e73e92bSScott Mayhew * If there's an error then the reply can have fewer ops than 36636e73e92bSScott Mayhew * the call. 366453da6a53SJ. Bruce Fields */ 36656e73e92bSScott Mayhew if (slot->sl_opcnt < argp->opcnt && !slot->sl_status) 36666e73e92bSScott Mayhew return false; 36676e73e92bSScott Mayhew /* 36686e73e92bSScott Mayhew * But if we cached a reply with *more* ops than the call you're 36696e73e92bSScott Mayhew * sending us now, then this new call is clearly not really a 36706e73e92bSScott Mayhew * replay of the old one: 36716e73e92bSScott Mayhew */ 36726e73e92bSScott Mayhew if (slot->sl_opcnt > argp->opcnt) 367353da6a53SJ. Bruce Fields return false; 367453da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 367553da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 367653da6a53SJ. Bruce Fields return false; 367753da6a53SJ. Bruce Fields /* 367853da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 367953da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 368053da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 368153da6a53SJ. Bruce Fields * the reply), so we don't bother. 368253da6a53SJ. Bruce Fields */ 368353da6a53SJ. Bruce Fields return true; 368453da6a53SJ. Bruce Fields } 368553da6a53SJ. Bruce Fields 3686069b6ad4SAndy Adamson __be32 3687eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3688eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3689069b6ad4SAndy Adamson { 3690eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3691f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 369247ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3693b85d4c01SBenny Halevy struct nfsd4_session *session; 3694221a6876SJ. Bruce Fields struct nfs4_client *clp; 3695b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3696a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 369757b7b43bSJ. Bruce Fields __be32 status; 369847ee5298SJ. Bruce Fields int buflen; 3699d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3700d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3701b85d4c01SBenny Halevy 3702f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3703f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3704f9bb94c4SAndy Adamson 3705a663bdd8SJ. Bruce Fields /* 3706a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3707a663bdd8SJ. Bruce Fields * below. 3708a663bdd8SJ. Bruce Fields */ 3709a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3710a663bdd8SJ. Bruce Fields if (!conn) 3711a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3712a663bdd8SJ. Bruce Fields 3713c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3714d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3715b85d4c01SBenny Halevy if (!session) 3716221a6876SJ. Bruce Fields goto out_no_session; 3717221a6876SJ. Bruce Fields clp = session->se_client; 3718b85d4c01SBenny Halevy 3719868b89c3SMi Jinlong status = nfserr_too_many_ops; 3720868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 372166b2b9b2SJ. Bruce Fields goto out_put_session; 3722868b89c3SMi Jinlong 3723ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3724ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 372566b2b9b2SJ. Bruce Fields goto out_put_session; 3726ae82a8d0SMi Jinlong 3727b85d4c01SBenny Halevy status = nfserr_badslot; 37286c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 372966b2b9b2SJ. Bruce Fields goto out_put_session; 3730b85d4c01SBenny Halevy 3731557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3732b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3733b85d4c01SBenny Halevy 3734a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3735a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3736a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3737a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 3738a8dfdaebSAndy Adamson 373973e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 374073e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 3741b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 3742bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 3743bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 374466b2b9b2SJ. Bruce Fields goto out_put_session; 374553da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 374653da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 374753da6a53SJ. Bruce Fields goto out_put_session; 3748b85d4c01SBenny Halevy cstate->slot = slot; 3749b85d4c01SBenny Halevy cstate->session = session; 37504b24ca7dSJeff Layton cstate->clp = clp; 3751da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 3752557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 3753bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 3754da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 3755aaf84eb9SBenny Halevy goto out; 3756b85d4c01SBenny Halevy } 3757b85d4c01SBenny Halevy if (status) 375866b2b9b2SJ. Bruce Fields goto out_put_session; 3759b85d4c01SBenny Halevy 376057266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 3761a663bdd8SJ. Bruce Fields conn = NULL; 376257266a6eSJ. Bruce Fields if (status) 376357266a6eSJ. Bruce Fields goto out_put_session; 3764328ead28SJ. Bruce Fields 376547ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 376647ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 376747ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 376847ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 376947ee5298SJ. Bruce Fields nfserr_rep_too_big; 3770a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 377147ee5298SJ. Bruce Fields goto out_put_session; 377232aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 377347ee5298SJ. Bruce Fields 377447ee5298SJ. Bruce Fields status = nfs_ok; 3775b85d4c01SBenny Halevy /* Success! bump slot seqid */ 3776b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 3777bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 377873e79482SJ. Bruce Fields if (seq->cachethis) 377973e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 3780bf5c43c8SJ. Bruce Fields else 3781bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 3782b85d4c01SBenny Halevy 3783b85d4c01SBenny Halevy cstate->slot = slot; 3784b85d4c01SBenny Halevy cstate->session = session; 37854b24ca7dSJeff Layton cstate->clp = clp; 3786b85d4c01SBenny Halevy 3787b85d4c01SBenny Halevy out: 37885423732aSBenny Halevy switch (clp->cl_cb_state) { 37895423732aSBenny Halevy case NFSD4_CB_DOWN: 3790fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 37915423732aSBenny Halevy break; 37925423732aSBenny Halevy case NFSD4_CB_FAULT: 3793fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 37945423732aSBenny Halevy break; 3795fc0c3dd1SBenny Halevy default: 3796fc0c3dd1SBenny Halevy seq->status_flags = 0; 37975423732aSBenny Halevy } 37983bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 37993bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 3800221a6876SJ. Bruce Fields out_no_session: 38013f42d2c4SKinglong Mee if (conn) 38023f42d2c4SKinglong Mee free_conn(conn); 3803c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3804b85d4c01SBenny Halevy return status; 380566b2b9b2SJ. Bruce Fields out_put_session: 3806d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 3807221a6876SJ. Bruce Fields goto out_no_session; 3808069b6ad4SAndy Adamson } 3809069b6ad4SAndy Adamson 3810b607664eSTrond Myklebust void 3811b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 3812b607664eSTrond Myklebust { 3813b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 3814b607664eSTrond Myklebust 3815b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 3816b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 3817b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 3818b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3819b607664eSTrond Myklebust } 3820d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 3821b607664eSTrond Myklebust nfsd4_put_session(cs->session); 38224b24ca7dSJeff Layton } else if (cs->clp) 38234b24ca7dSJeff Layton put_client_renew(cs->clp); 3824b607664eSTrond Myklebust } 3825b607664eSTrond Myklebust 3826345c2842SMi Jinlong __be32 3827eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 3828eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3829eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3830345c2842SMi Jinlong { 3831eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 38326b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 38336b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 383457b7b43bSJ. Bruce Fields __be32 status = 0; 38358daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3836345c2842SMi Jinlong 38376b10ad19STrond Myklebust spin_lock(&nn->client_lock); 38380a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 38398daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 384078389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3841345c2842SMi Jinlong 3842345c2842SMi Jinlong if (conf) { 3843c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 3844345c2842SMi Jinlong status = nfserr_clientid_busy; 3845345c2842SMi Jinlong goto out; 3846345c2842SMi Jinlong } 3847fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3848fd699b8aSJeff Layton if (status) 3849fd699b8aSJeff Layton goto out; 38506b10ad19STrond Myklebust clp = conf; 3851345c2842SMi Jinlong } else if (unconf) 3852345c2842SMi Jinlong clp = unconf; 3853345c2842SMi Jinlong else { 3854345c2842SMi Jinlong status = nfserr_stale_clientid; 3855345c2842SMi Jinlong goto out; 3856345c2842SMi Jinlong } 3857dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 38586b10ad19STrond Myklebust clp = NULL; 385957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 386057266a6eSJ. Bruce Fields goto out; 386157266a6eSJ. Bruce Fields } 38626b10ad19STrond Myklebust unhash_client_locked(clp); 3863345c2842SMi Jinlong out: 38646b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 38656b10ad19STrond Myklebust if (clp) 38666b10ad19STrond Myklebust expire_client(clp); 3867345c2842SMi Jinlong return status; 3868345c2842SMi Jinlong } 3869345c2842SMi Jinlong 3870069b6ad4SAndy Adamson __be32 3871eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 3872eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 38734dc6ec00SJ. Bruce Fields { 3874eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 387557b7b43bSJ. Bruce Fields __be32 status = 0; 3876bcecf1ccSMi Jinlong 38774dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 38784dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 38794dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 38804dc6ec00SJ. Bruce Fields /* 38814dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 38824dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 38834dc6ec00SJ. Bruce Fields */ 38844dc6ec00SJ. Bruce Fields return nfs_ok; 38854dc6ec00SJ. Bruce Fields } 3886bcecf1ccSMi Jinlong 3887bcecf1ccSMi Jinlong status = nfserr_complete_already; 3888a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 3889a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 3890bcecf1ccSMi Jinlong goto out; 3891bcecf1ccSMi Jinlong 3892bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 3893bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 38944dc6ec00SJ. Bruce Fields /* 38954dc6ec00SJ. Bruce Fields * The following error isn't really legal. 38964dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 38974dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 38984dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 38994dc6ec00SJ. Bruce Fields * client. 39004dc6ec00SJ. Bruce Fields */ 3901bcecf1ccSMi Jinlong goto out; 3902bcecf1ccSMi Jinlong 3903bcecf1ccSMi Jinlong status = nfs_ok; 39042a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 3905362063a5SScott Mayhew inc_reclaim_complete(cstate->session->se_client); 3906bcecf1ccSMi Jinlong out: 3907bcecf1ccSMi Jinlong return status; 39084dc6ec00SJ. Bruce Fields } 39094dc6ec00SJ. Bruce Fields 39104dc6ec00SJ. Bruce Fields __be32 3911b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3912eb69853dSChristoph Hellwig union nfsd4_op_u *u) 39131da177e4SLinus Torvalds { 3914eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 3915a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 39161da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 39173dbacee6STrond Myklebust struct nfs4_client *conf, *new; 39183dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 3919b37ad28bSAl Viro __be32 status; 3920c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3921a55370a3SNeilBrown 39225cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 39235cc40fd7STrond Myklebust if (new == NULL) 39245cc40fd7STrond Myklebust return nfserr_jukebox; 392563db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 39263dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3927382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 39282b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 392963db4632SJ. Bruce Fields /* case 0: */ 39301da177e4SLinus Torvalds status = nfserr_clid_inuse; 3931e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 3932e203d506SJ. Bruce Fields goto out; 3933026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 3934dd5e3fbcSChuck Lever trace_nfsd_clid_inuse_err(conf); 39351da177e4SLinus Torvalds goto out; 39361da177e4SLinus Torvalds } 39371da177e4SLinus Torvalds } 3938a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 39391da177e4SLinus Torvalds if (unconf) 39403dbacee6STrond Myklebust unhash_client_locked(unconf); 394145f56da8SChuck Lever /* We need to handle only case 1: probable callback update */ 394241eb1670SKinglong Mee if (conf && same_verf(&conf->cl_verifier, &clverifier)) { 39431da177e4SLinus Torvalds copy_clid(new, conf); 394441eb1670SKinglong Mee gen_confirm(new, nn); 394545f56da8SChuck Lever } 39468323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 39476f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 3948ac55fdc4SJeff Layton add_to_unconfirmed(new); 39491da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 39501da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 39511da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 39525cc40fd7STrond Myklebust new = NULL; 39531da177e4SLinus Torvalds status = nfs_ok; 39541da177e4SLinus Torvalds out: 39553dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 39565cc40fd7STrond Myklebust if (new) 39575cc40fd7STrond Myklebust free_client(new); 39583dbacee6STrond Myklebust if (unconf) 39593dbacee6STrond Myklebust expire_client(unconf); 39601da177e4SLinus Torvalds return status; 39611da177e4SLinus Torvalds } 39621da177e4SLinus Torvalds 39631da177e4SLinus Torvalds 3964b37ad28bSAl Viro __be32 3965b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 3966b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 3967eb69853dSChristoph Hellwig union nfsd4_op_u *u) 39681da177e4SLinus Torvalds { 3969eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 3970eb69853dSChristoph Hellwig &u->setclientid_confirm; 397121ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 3972d20c11d8SJeff Layton struct nfs4_client *old = NULL; 39731da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 39741da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 3975b37ad28bSAl Viro __be32 status; 39767f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 39771da177e4SLinus Torvalds 39782c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 39791da177e4SLinus Torvalds return nfserr_stale_clientid; 398021ab45a4SNeilBrown 3981d20c11d8SJeff Layton spin_lock(&nn->client_lock); 39828daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 39830a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 3984a186e767SJ. Bruce Fields /* 39858695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 39868695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 3987f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 3988f984a7ceSJ. Bruce Fields * 3989f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 3990a186e767SJ. Bruce Fields */ 3991f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 39928695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 39938695b90aSJ. Bruce Fields goto out; 39948695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 39958695b90aSJ. Bruce Fields goto out; 399663db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 399790d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 39987d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 39997d22fc11SJ. Bruce Fields /* case 2: probable retransmit */ 400090d700b7SJ. Bruce Fields status = nfs_ok; 40017d22fc11SJ. Bruce Fields } else /* case 4: client hasn't noticed we rebooted yet? */ 400290d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 400390d700b7SJ. Bruce Fields goto out; 400490d700b7SJ. Bruce Fields } 400590d700b7SJ. Bruce Fields status = nfs_ok; 400690d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 4007d20c11d8SJeff Layton old = unconf; 4008d20c11d8SJeff Layton unhash_client_locked(old); 40095a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 401090d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 4011d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 4012d20c11d8SJeff Layton if (old) { 40132b634821SJ. Bruce Fields status = nfserr_clid_inuse; 40142b634821SJ. Bruce Fields if (client_has_state(old) 40152b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 40162b634821SJ. Bruce Fields &old->cl_cred)) 40172b634821SJ. Bruce Fields goto out; 4018d20c11d8SJeff Layton status = mark_client_expired_locked(old); 40197abea1e8SJeff Layton if (status) { 40207abea1e8SJeff Layton old = NULL; 4021221a6876SJ. Bruce Fields goto out; 4022221a6876SJ. Bruce Fields } 40237abea1e8SJeff Layton } 40241da177e4SLinus Torvalds move_to_confirmed(unconf); 4025d20c11d8SJeff Layton conf = unconf; 402608e8987cSNeilBrown } 4027d20c11d8SJeff Layton get_client_locked(conf); 4028d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4029d20c11d8SJeff Layton nfsd4_probe_callback(conf); 4030d20c11d8SJeff Layton spin_lock(&nn->client_lock); 4031d20c11d8SJeff Layton put_client_renew_locked(conf); 40321da177e4SLinus Torvalds out: 4033d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4034d20c11d8SJeff Layton if (old) 4035d20c11d8SJeff Layton expire_client(old); 40361da177e4SLinus Torvalds return status; 40371da177e4SLinus Torvalds } 40381da177e4SLinus Torvalds 403932513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 40401da177e4SLinus Torvalds { 404132513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 404232513b40SJ. Bruce Fields } 404332513b40SJ. Bruce Fields 404432513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 40455b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, 40465b095e99SJeff Layton struct nfs4_file *fp) 404732513b40SJ. Bruce Fields { 4048950e0118STrond Myklebust lockdep_assert_held(&state_lock); 4049950e0118STrond Myklebust 4050818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 40511d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 40528beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 40538beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 40548287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 4055e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 40560c637be8SJeff Layton fp->fi_deleg_file = NULL; 405747f9940cSMeelap Shah fp->fi_had_conflict = false; 4058baeb4ff0SJeff Layton fp->fi_share_deny = 0; 4059f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 4060f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 40619cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 40629cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 4063c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 40649cf514ccSChristoph Hellwig #endif 40655b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 40661da177e4SLinus Torvalds } 40671da177e4SLinus Torvalds 4068e8ff2a84SJ. Bruce Fields void 4069e60d4398SNeilBrown nfsd4_free_slabs(void) 4070e60d4398SNeilBrown { 40719258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4072abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 4073abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4074abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4075abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4076abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 40779258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 4078e60d4398SNeilBrown } 40791da177e4SLinus Torvalds 408072083396SBryan Schumaker int 40811da177e4SLinus Torvalds nfsd4_init_slabs(void) 40821da177e4SLinus Torvalds { 40839258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 40849258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 40859258a2d5SJeff Layton if (client_slab == NULL) 40869258a2d5SJeff Layton goto out; 4087fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 4088fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 4089fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 40909258a2d5SJeff Layton goto out_free_client_slab; 4091fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 40923c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 4093fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 4094abf1135bSChristoph Hellwig goto out_free_openowner_slab; 4095e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 409620c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 4097e60d4398SNeilBrown if (file_slab == NULL) 4098abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 40995ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 4100dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 41015ac049acSNeilBrown if (stateid_slab == NULL) 4102abf1135bSChristoph Hellwig goto out_free_file_slab; 41035b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 410420c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 41055b2d21c1SNeilBrown if (deleg_slab == NULL) 4106abf1135bSChristoph Hellwig goto out_free_stateid_slab; 41078287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 41088287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 41098287f009SSachin Bhamare if (odstate_slab == NULL) 41108287f009SSachin Bhamare goto out_free_deleg_slab; 4111e60d4398SNeilBrown return 0; 4112abf1135bSChristoph Hellwig 41138287f009SSachin Bhamare out_free_deleg_slab: 41148287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 4115abf1135bSChristoph Hellwig out_free_stateid_slab: 4116abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4117abf1135bSChristoph Hellwig out_free_file_slab: 4118abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4119abf1135bSChristoph Hellwig out_free_lockowner_slab: 4120abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4121abf1135bSChristoph Hellwig out_free_openowner_slab: 4122abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 41239258a2d5SJeff Layton out_free_client_slab: 41249258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4125abf1135bSChristoph Hellwig out: 41261da177e4SLinus Torvalds return -ENOMEM; 41271da177e4SLinus Torvalds } 41281da177e4SLinus Torvalds 4129ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 4130ff194bd9SJ. Bruce Fields { 4131ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 4132ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 4133ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 413458fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 413558fb12e6SJeff Layton } 413658fb12e6SJeff Layton 413758fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 413858fb12e6SJeff Layton struct nfs4_stateowner *so) 413958fb12e6SJeff Layton { 414058fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 414158fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 4142b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 414358fb12e6SJeff Layton } 414458fb12e6SJeff Layton } 414558fb12e6SJeff Layton 414658fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 414758fb12e6SJeff Layton { 414858fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 414958fb12e6SJeff Layton 415058fb12e6SJeff Layton if (so != NULL) { 415158fb12e6SJeff Layton cstate->replay_owner = NULL; 415258fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 415358fb12e6SJeff Layton nfs4_put_stateowner(so); 415458fb12e6SJeff Layton } 4155ff194bd9SJ. Bruce Fields } 4156ff194bd9SJ. Bruce Fields 4157fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 41581da177e4SLinus Torvalds { 41591da177e4SLinus Torvalds struct nfs4_stateowner *sop; 41601da177e4SLinus Torvalds 4161fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 4162ff194bd9SJ. Bruce Fields if (!sop) 4163ff194bd9SJ. Bruce Fields return NULL; 4164ff194bd9SJ. Bruce Fields 41656f4859b8SJ. Bruce Fields xdr_netobj_dup(&sop->so_owner, owner, GFP_KERNEL); 4166ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 4167fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 4168ff194bd9SJ. Bruce Fields return NULL; 4169ff194bd9SJ. Bruce Fields } 4170ff194bd9SJ. Bruce Fields 4171ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 4172ff194bd9SJ. Bruce Fields sop->so_client = clp; 4173ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 41746b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 41751da177e4SLinus Torvalds return sop; 41761da177e4SLinus Torvalds } 4177ff194bd9SJ. Bruce Fields 4178fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 4179ff194bd9SJ. Bruce Fields { 4180d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 41819b531137SStanislav Kinsbursky 4182d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 4183d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 4184fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 41851da177e4SLinus Torvalds } 41861da177e4SLinus Torvalds 41878f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 41888f4b54c5SJeff Layton { 4189d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 41908f4b54c5SJeff Layton } 41918f4b54c5SJeff Layton 41926b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 41936b180f0bSJeff Layton { 41946b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 41956b180f0bSJeff Layton 41966b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 41976b180f0bSJeff Layton } 41986b180f0bSJeff Layton 41996b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 42008f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 42016b180f0bSJeff Layton .so_free = nfs4_free_openowner, 42026b180f0bSJeff Layton }; 42036b180f0bSJeff Layton 42047fc0564eSAndrew Elble static struct nfs4_ol_stateid * 42057fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 42067fc0564eSAndrew Elble { 42077fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 42087fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 42097fc0564eSAndrew Elble 42107fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 42117fc0564eSAndrew Elble 42127fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 42137fc0564eSAndrew Elble /* ignore lock owners */ 42147fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 42157fc0564eSAndrew Elble continue; 421615ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 421715ca08d3STrond Myklebust continue; 421815ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 42197fc0564eSAndrew Elble ret = local; 4220a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 42217fc0564eSAndrew Elble break; 42227fc0564eSAndrew Elble } 42237fc0564eSAndrew Elble } 42247fc0564eSAndrew Elble return ret; 42257fc0564eSAndrew Elble } 42267fc0564eSAndrew Elble 422715ca08d3STrond Myklebust static __be32 422815ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 422915ca08d3STrond Myklebust { 423015ca08d3STrond Myklebust __be32 ret = nfs_ok; 423115ca08d3STrond Myklebust 423215ca08d3STrond Myklebust switch (s->sc_type) { 423315ca08d3STrond Myklebust default: 423415ca08d3STrond Myklebust break; 42354f176417STrond Myklebust case 0: 423615ca08d3STrond Myklebust case NFS4_CLOSED_STID: 423715ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 423815ca08d3STrond Myklebust ret = nfserr_bad_stateid; 423915ca08d3STrond Myklebust break; 424015ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 424115ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 424215ca08d3STrond Myklebust } 424315ca08d3STrond Myklebust return ret; 424415ca08d3STrond Myklebust } 424515ca08d3STrond Myklebust 424615ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 424715ca08d3STrond Myklebust static __be32 424815ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 424915ca08d3STrond Myklebust { 425015ca08d3STrond Myklebust __be32 ret; 425115ca08d3STrond Myklebust 42524f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 425315ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 425415ca08d3STrond Myklebust if (ret != nfs_ok) 425515ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 425615ca08d3STrond Myklebust return ret; 425715ca08d3STrond Myklebust } 425815ca08d3STrond Myklebust 425915ca08d3STrond Myklebust static struct nfs4_ol_stateid * 426015ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 426115ca08d3STrond Myklebust { 426215ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 426315ca08d3STrond Myklebust for (;;) { 426415ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 426515ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 426615ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 426715ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 426815ca08d3STrond Myklebust break; 426915ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 427015ca08d3STrond Myklebust } 427115ca08d3STrond Myklebust return stp; 427215ca08d3STrond Myklebust } 427315ca08d3STrond Myklebust 4274fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 427513d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 4276db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 4277db24b3b4SJeff Layton { 427813d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 42797ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 42801da177e4SLinus Torvalds 4281fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 4282fe0750e5SJ. Bruce Fields if (!oo) 42831da177e4SLinus Torvalds return NULL; 42846b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 4285fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 4286fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 4287d3134b10SJeff Layton oo->oo_flags = 0; 4288db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 4289db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 4290fe0750e5SJ. Bruce Fields oo->oo_time = 0; 429138c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 4292fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 4293d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 4294d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 42957ffb5880STrond Myklebust if (ret == NULL) { 4296fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 42977ffb5880STrond Myklebust ret = oo; 42987ffb5880STrond Myklebust } else 4299d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 4300d50ffdedSKinglong Mee 4301d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 4302c5952338SJeff Layton return ret; 43031da177e4SLinus Torvalds } 43041da177e4SLinus Torvalds 43057fc0564eSAndrew Elble static struct nfs4_ol_stateid * 43068c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 43077fc0564eSAndrew Elble { 43081da177e4SLinus Torvalds 43097fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 43107fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 43118c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 43127fc0564eSAndrew Elble 43138c7245abSOleg Drokin stp = open->op_stp; 43145cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 43155cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 43164f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 43175cc1fb2aSOleg Drokin 431815ca08d3STrond Myklebust retry: 43197fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 43207fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 43217fc0564eSAndrew Elble 43227fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 43237fc0564eSAndrew Elble if (retstp) 43247fc0564eSAndrew Elble goto out_unlock; 43258c7245abSOleg Drokin 43268c7245abSOleg Drokin open->op_stp = NULL; 4327a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 43283abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 43293c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 4330b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 433113cd2184SNeilBrown get_nfs4_file(fp); 433211b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 43331da177e4SLinus Torvalds stp->st_access_bmap = 0; 43341da177e4SLinus Torvalds stp->st_deny_bmap = 0; 43354c4cd222SNeilBrown stp->st_openstp = NULL; 43361c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 43371d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 43387fc0564eSAndrew Elble 43397fc0564eSAndrew Elble out_unlock: 43401d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 43411c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 43425cc1fb2aSOleg Drokin if (retstp) { 434315ca08d3STrond Myklebust /* Handle races with CLOSE */ 434415ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 434515ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 434615ca08d3STrond Myklebust goto retry; 434715ca08d3STrond Myklebust } 43488c7245abSOleg Drokin /* To keep mutex tracking happy */ 43495cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 43508c7245abSOleg Drokin stp = retstp; 43515cc1fb2aSOleg Drokin } 43528c7245abSOleg Drokin return stp; 43531da177e4SLinus Torvalds } 43541da177e4SLinus Torvalds 4355d3134b10SJeff Layton /* 4356d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 4357d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 4358d3134b10SJeff Layton * them before returning however. 4359d3134b10SJeff Layton */ 43601da177e4SLinus Torvalds static void 4361d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 43621da177e4SLinus Torvalds { 4363217526e7SJeff Layton struct nfs4_ol_stateid *last; 4364d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 4365d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 4366d3134b10SJeff Layton nfsd_net_id); 436773758fedSStanislav Kinsbursky 4368fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 43691da177e4SLinus Torvalds 4370b401be22SJeff Layton /* 4371b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 4372b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 4373b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 4374b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 4375b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 4376b401be22SJeff Layton * there should be no danger of the refcount going back up again at 4377b401be22SJeff Layton * this point. 4378b401be22SJeff Layton */ 4379a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 4380b401be22SJeff Layton 4381d3134b10SJeff Layton release_all_access(s); 4382d3134b10SJeff Layton if (s->st_stid.sc_file) { 4383d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 4384d3134b10SJeff Layton s->st_stid.sc_file = NULL; 4385d3134b10SJeff Layton } 4386217526e7SJeff Layton 4387217526e7SJeff Layton spin_lock(&nn->client_lock); 4388217526e7SJeff Layton last = oo->oo_last_closed_stid; 4389d3134b10SJeff Layton oo->oo_last_closed_stid = s; 439073758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 439120b7d86fSArnd Bergmann oo->oo_time = ktime_get_boottime_seconds(); 4392217526e7SJeff Layton spin_unlock(&nn->client_lock); 4393217526e7SJeff Layton if (last) 4394217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 43951da177e4SLinus Torvalds } 43961da177e4SLinus Torvalds 43971da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 43981da177e4SLinus Torvalds static struct nfs4_file * 43995b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval) 44001da177e4SLinus Torvalds { 44011da177e4SLinus Torvalds struct nfs4_file *fp; 44021da177e4SLinus Torvalds 440336a80491SMadhuparna Bhowmik hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, 440436a80491SMadhuparna Bhowmik lockdep_is_held(&state_lock)) { 44054d94c2efSChristoph Hellwig if (fh_match(&fp->fi_fhandle, fh)) { 4406818a34ebSElena Reshetova if (refcount_inc_not_zero(&fp->fi_ref)) 44071da177e4SLinus Torvalds return fp; 44081da177e4SLinus Torvalds } 440913cd2184SNeilBrown } 44101da177e4SLinus Torvalds return NULL; 44111da177e4SLinus Torvalds } 44121da177e4SLinus Torvalds 4413e6ba76e1SChristoph Hellwig struct nfs4_file * 4414ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 4415950e0118STrond Myklebust { 4416950e0118STrond Myklebust struct nfs4_file *fp; 44175b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 4418950e0118STrond Myklebust 44195b095e99SJeff Layton rcu_read_lock(); 44205b095e99SJeff Layton fp = find_file_locked(fh, hashval); 44215b095e99SJeff Layton rcu_read_unlock(); 4422950e0118STrond Myklebust return fp; 4423950e0118STrond Myklebust } 4424950e0118STrond Myklebust 4425950e0118STrond Myklebust static struct nfs4_file * 4426f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 4427950e0118STrond Myklebust { 4428950e0118STrond Myklebust struct nfs4_file *fp; 44295b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 44305b095e99SJeff Layton 44315b095e99SJeff Layton rcu_read_lock(); 44325b095e99SJeff Layton fp = find_file_locked(fh, hashval); 44335b095e99SJeff Layton rcu_read_unlock(); 44345b095e99SJeff Layton if (fp) 44355b095e99SJeff Layton return fp; 4436950e0118STrond Myklebust 4437950e0118STrond Myklebust spin_lock(&state_lock); 44385b095e99SJeff Layton fp = find_file_locked(fh, hashval); 44395b095e99SJeff Layton if (likely(fp == NULL)) { 44405b095e99SJeff Layton nfsd4_init_file(fh, hashval, new); 4441950e0118STrond Myklebust fp = new; 4442950e0118STrond Myklebust } 4443950e0118STrond Myklebust spin_unlock(&state_lock); 4444950e0118STrond Myklebust 4445950e0118STrond Myklebust return fp; 4446950e0118STrond Myklebust } 4447950e0118STrond Myklebust 44484f83aa30SJ. Bruce Fields /* 44491da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 44501da177e4SLinus Torvalds * WRITE with all zero or all one stateid 44511da177e4SLinus Torvalds */ 4452b37ad28bSAl Viro static __be32 44531da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 44541da177e4SLinus Torvalds { 44551da177e4SLinus Torvalds struct nfs4_file *fp; 4456baeb4ff0SJeff Layton __be32 ret = nfs_ok; 44571da177e4SLinus Torvalds 4458ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 445913cd2184SNeilBrown if (!fp) 4460baeb4ff0SJeff Layton return ret; 4461baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 44621d31a253STrond Myklebust spin_lock(&fp->fi_lock); 4463baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 4464baeb4ff0SJeff Layton ret = nfserr_locked; 44651d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 446613cd2184SNeilBrown put_nfs4_file(fp); 446713cd2184SNeilBrown return ret; 44681da177e4SLinus Torvalds } 44691da177e4SLinus Torvalds 44700162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 44711da177e4SLinus Torvalds { 44720162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 447311b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 447411b9164aSTrond Myklebust nfsd_net_id); 4475e8c69d17SJ. Bruce Fields 447611b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 4477f54fe962SJeff Layton 447802e1215fSJeff Layton /* 447902e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 4480f54fe962SJeff Layton * already holding inode->i_lock. 4481f54fe962SJeff Layton * 4482dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 4483dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 4484dff1399fSJeff Layton */ 4485f54fe962SJeff Layton spin_lock(&state_lock); 4486dff1399fSJeff Layton if (dp->dl_time == 0) { 448720b7d86fSArnd Bergmann dp->dl_time = ktime_get_boottime_seconds(); 448802e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 448902e1215fSJeff Layton } 449002e1215fSJeff Layton spin_unlock(&state_lock); 4491dff1399fSJeff Layton } 44921da177e4SLinus Torvalds 44930162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 44940162ac2bSChristoph Hellwig struct rpc_task *task) 44950162ac2bSChristoph Hellwig { 44960162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 44970162ac2bSChristoph Hellwig 4498a457974fSAndrew Elble if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID) 4499a457974fSAndrew Elble return 1; 4500a457974fSAndrew Elble 45010162ac2bSChristoph Hellwig switch (task->tk_status) { 45020162ac2bSChristoph Hellwig case 0: 45030162ac2bSChristoph Hellwig return 1; 45041c73b9d2SScott Mayhew case -NFS4ERR_DELAY: 45051c73b9d2SScott Mayhew rpc_delay(task, 2 * HZ); 45061c73b9d2SScott Mayhew return 0; 45070162ac2bSChristoph Hellwig case -EBADHANDLE: 45080162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 45090162ac2bSChristoph Hellwig /* 45100162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 45110162ac2bSChristoph Hellwig * granting delegation. 45120162ac2bSChristoph Hellwig */ 45130162ac2bSChristoph Hellwig if (dp->dl_retries--) { 45140162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 45150162ac2bSChristoph Hellwig return 0; 45160162ac2bSChristoph Hellwig } 45170162ac2bSChristoph Hellwig /*FALLTHRU*/ 45180162ac2bSChristoph Hellwig default: 45191c73b9d2SScott Mayhew return 1; 45200162ac2bSChristoph Hellwig } 45210162ac2bSChristoph Hellwig } 45220162ac2bSChristoph Hellwig 45230162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 45240162ac2bSChristoph Hellwig { 45250162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 45260162ac2bSChristoph Hellwig 45270162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 45280162ac2bSChristoph Hellwig } 45290162ac2bSChristoph Hellwig 4530c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 45310162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 45320162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 45330162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 45340162ac2bSChristoph Hellwig }; 45350162ac2bSChristoph Hellwig 453602e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 453702e1215fSJeff Layton { 453802e1215fSJeff Layton /* 453902e1215fSJeff Layton * We're assuming the state code never drops its reference 454002e1215fSJeff Layton * without first removing the lease. Since we're in this lease 45414a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 45424a269efbSJ. Bruce Fields * i_lock) we know the server hasn't removed the lease yet, and 45434a269efbSJ. Bruce Fields * we know it's safe to take a reference. 454402e1215fSJeff Layton */ 4545a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 4546f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 45476b57d9c8SJ. Bruce Fields } 45486b57d9c8SJ. Bruce Fields 45491c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 45504d01b7f5SJeff Layton static bool 45514d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 45526b57d9c8SJ. Bruce Fields { 45534d01b7f5SJeff Layton bool ret = false; 4554653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 4555653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 45566b57d9c8SJ. Bruce Fields 4557dd5e3fbcSChuck Lever trace_nfsd_deleg_break(&dp->dl_stid.sc_stateid); 4558dd5e3fbcSChuck Lever 45590272e1fdSJ. Bruce Fields /* 45600272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 4561acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 45626b57d9c8SJ. Bruce Fields * in time: 45630272e1fdSJ. Bruce Fields */ 45640272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 45651da177e4SLinus Torvalds 456602e1215fSJeff Layton spin_lock(&fp->fi_lock); 4567417c6629SJeff Layton fp->fi_had_conflict = true; 45685d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 456902e1215fSJeff Layton spin_unlock(&fp->fi_lock); 45704d01b7f5SJeff Layton return ret; 45711da177e4SLinus Torvalds } 45721da177e4SLinus Torvalds 457328df3d15SJ. Bruce Fields static bool nfsd_breaker_owns_lease(struct file_lock *fl) 457428df3d15SJ. Bruce Fields { 457528df3d15SJ. Bruce Fields struct nfs4_delegation *dl = fl->fl_owner; 457628df3d15SJ. Bruce Fields struct svc_rqst *rqst; 457728df3d15SJ. Bruce Fields struct nfs4_client *clp; 457828df3d15SJ. Bruce Fields 457928df3d15SJ. Bruce Fields if (!i_am_nfsd()) 458028df3d15SJ. Bruce Fields return NULL; 458128df3d15SJ. Bruce Fields rqst = kthread_data(current); 458228df3d15SJ. Bruce Fields clp = *(rqst->rq_lease_breaker); 458328df3d15SJ. Bruce Fields return dl->dl_stid.sc_client == clp; 458428df3d15SJ. Bruce Fields } 458528df3d15SJ. Bruce Fields 4586c45198edSJeff Layton static int 45877448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 45887448cc37SJeff Layton struct list_head *dispose) 45891da177e4SLinus Torvalds { 45901da177e4SLinus Torvalds if (arg & F_UNLCK) 4591c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 45921da177e4SLinus Torvalds else 45931da177e4SLinus Torvalds return -EAGAIN; 45941da177e4SLinus Torvalds } 45951da177e4SLinus Torvalds 45967b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 459728df3d15SJ. Bruce Fields .lm_breaker_owns_lease = nfsd_breaker_owns_lease, 45988fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 45998fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 46001da177e4SLinus Torvalds }; 46011da177e4SLinus Torvalds 46027a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 46037a8711c9SJ. Bruce Fields { 46047a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 46057a8711c9SJ. Bruce Fields return nfs_ok; 46067a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 46077a8711c9SJ. Bruce Fields return nfserr_replay_me; 46087a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 46097a8711c9SJ. Bruce Fields return nfs_ok; 46107a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 46117a8711c9SJ. Bruce Fields } 46121da177e4SLinus Torvalds 46134b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 46144b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 4615b7342204SOlga Kornievskaia struct nfsd_net *nn, 4616b7342204SOlga Kornievskaia bool sessions) 46174b24ca7dSJeff Layton { 46184b24ca7dSJeff Layton struct nfs4_client *found; 46194b24ca7dSJeff Layton 46204b24ca7dSJeff Layton if (cstate->clp) { 46214b24ca7dSJeff Layton found = cstate->clp; 46224b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 46234b24ca7dSJeff Layton return nfserr_stale_clientid; 46244b24ca7dSJeff Layton return nfs_ok; 46254b24ca7dSJeff Layton } 46264b24ca7dSJeff Layton 46274b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 46284b24ca7dSJeff Layton return nfserr_stale_clientid; 46294b24ca7dSJeff Layton 46304b24ca7dSJeff Layton /* 46314b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 46324b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 46334b24ca7dSJeff Layton * will be false. 46344b24ca7dSJeff Layton */ 46354b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 46363e339f96STrond Myklebust spin_lock(&nn->client_lock); 4637b7342204SOlga Kornievskaia found = find_confirmed_client(clid, sessions, nn); 46383e339f96STrond Myklebust if (!found) { 46393e339f96STrond Myklebust spin_unlock(&nn->client_lock); 46404b24ca7dSJeff Layton return nfserr_expired; 46413e339f96STrond Myklebust } 464214ed14ccSJ. Bruce Fields atomic_inc(&found->cl_rpc_users); 46433e339f96STrond Myklebust spin_unlock(&nn->client_lock); 46444b24ca7dSJeff Layton 46454b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 46464b24ca7dSJeff Layton cstate->clp = found; 46474b24ca7dSJeff Layton return nfs_ok; 46484b24ca7dSJeff Layton } 46494b24ca7dSJeff Layton 4650b37ad28bSAl Viro __be32 46516668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 46523320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 46531da177e4SLinus Torvalds { 46541da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 46551da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 46561da177e4SLinus Torvalds unsigned int strhashval; 4657fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 46584cdc951bSJ. Bruce Fields __be32 status; 46591da177e4SLinus Torvalds 46602c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 46611da177e4SLinus Torvalds return nfserr_stale_clientid; 466232513b40SJ. Bruce Fields /* 466332513b40SJ. Bruce Fields * In case we need it later, after we've already created the 466432513b40SJ. Bruce Fields * file and don't want to risk a further failure: 466532513b40SJ. Bruce Fields */ 466632513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 466732513b40SJ. Bruce Fields if (open->op_file == NULL) 466832513b40SJ. Bruce Fields return nfserr_jukebox; 46691da177e4SLinus Torvalds 4670b7342204SOlga Kornievskaia status = lookup_clientid(clientid, cstate, nn, false); 467113d6f66bSTrond Myklebust if (status) 467213d6f66bSTrond Myklebust return status; 467313d6f66bSTrond Myklebust clp = cstate->clp; 46742d91e895STrond Myklebust 4675d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 4676d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 46772d91e895STrond Myklebust open->op_openowner = oo; 46782d91e895STrond Myklebust if (!oo) { 4679bcf130f9SJ. Bruce Fields goto new_owner; 46800f442aa2SJ. Bruce Fields } 4681dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 46820f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 4683fe0750e5SJ. Bruce Fields release_openowner(oo); 4684fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 4685bcf130f9SJ. Bruce Fields goto new_owner; 46860f442aa2SJ. Bruce Fields } 46874cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 46884cdc951bSJ. Bruce Fields if (status) 46894cdc951bSJ. Bruce Fields return status; 46904cdc951bSJ. Bruce Fields goto alloc_stateid; 4691bcf130f9SJ. Bruce Fields new_owner: 469213d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 4693fe0750e5SJ. Bruce Fields if (oo == NULL) 46943e772463SJ. Bruce Fields return nfserr_jukebox; 4695fe0750e5SJ. Bruce Fields open->op_openowner = oo; 46964cdc951bSJ. Bruce Fields alloc_stateid: 4697b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 46984cdc951bSJ. Bruce Fields if (!open->op_stp) 46994cdc951bSJ. Bruce Fields return nfserr_jukebox; 47008287f009SSachin Bhamare 47018287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 47028287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 47038287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 47048287f009SSachin Bhamare if (!open->op_odstate) 47058287f009SSachin Bhamare return nfserr_jukebox; 47068287f009SSachin Bhamare } 47078287f009SSachin Bhamare 47080f442aa2SJ. Bruce Fields return nfs_ok; 47091da177e4SLinus Torvalds } 47101da177e4SLinus Torvalds 4711b37ad28bSAl Viro static inline __be32 47124a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 47134a6e43e6SNeilBrown { 47144a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 47154a6e43e6SNeilBrown return nfserr_openmode; 47164a6e43e6SNeilBrown else 47174a6e43e6SNeilBrown return nfs_ok; 47184a6e43e6SNeilBrown } 47194a6e43e6SNeilBrown 4720c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 472124a0111eSJ. Bruce Fields { 472224a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 472324a0111eSJ. Bruce Fields } 472424a0111eSJ. Bruce Fields 472538c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 4726f459e453SJ. Bruce Fields { 4727f459e453SJ. Bruce Fields struct nfs4_stid *ret; 4728f459e453SJ. Bruce Fields 472995da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 473095da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 4731f459e453SJ. Bruce Fields if (!ret) 4732f459e453SJ. Bruce Fields return NULL; 4733f459e453SJ. Bruce Fields return delegstateid(ret); 4734f459e453SJ. Bruce Fields } 4735f459e453SJ. Bruce Fields 47368b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 47378b289b2cSJ. Bruce Fields { 47388b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 47398b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 47408b289b2cSJ. Bruce Fields } 47418b289b2cSJ. Bruce Fields 4742b37ad28bSAl Viro static __be32 474341d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 4744567d9829SNeilBrown struct nfs4_delegation **dp) 4745567d9829SNeilBrown { 4746567d9829SNeilBrown int flags; 4747b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 4748dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 4749567d9829SNeilBrown 4750dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 4751dcd94cc2STrond Myklebust if (deleg == NULL) 4752c44c5eebSNeilBrown goto out; 475395da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 475495da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 475595da1b3aSAndrew Elble if (cl->cl_minorversion) 475695da1b3aSAndrew Elble status = nfserr_deleg_revoked; 475795da1b3aSAndrew Elble goto out; 475895da1b3aSAndrew Elble } 475924a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 4760dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 4761dcd94cc2STrond Myklebust if (status) { 4762dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 4763dcd94cc2STrond Myklebust goto out; 4764dcd94cc2STrond Myklebust } 4765dcd94cc2STrond Myklebust *dp = deleg; 4766c44c5eebSNeilBrown out: 47678b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 4768c44c5eebSNeilBrown return nfs_ok; 4769c44c5eebSNeilBrown if (status) 4770c44c5eebSNeilBrown return status; 4771dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 4772c44c5eebSNeilBrown return nfs_ok; 4773567d9829SNeilBrown } 4774567d9829SNeilBrown 477521fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 477621fb4016SJ. Bruce Fields { 477721fb4016SJ. Bruce Fields int flags = 0; 477821fb4016SJ. Bruce Fields 477921fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 478021fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 478121fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 478221fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 478321fb4016SJ. Bruce Fields return flags; 478421fb4016SJ. Bruce Fields } 478521fb4016SJ. Bruce Fields 4786b37ad28bSAl Viro static inline __be32 47871da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 47881da177e4SLinus Torvalds struct nfsd4_open *open) 47891da177e4SLinus Torvalds { 47901da177e4SLinus Torvalds struct iattr iattr = { 47911da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 47921da177e4SLinus Torvalds .ia_size = 0, 47931da177e4SLinus Torvalds }; 47941da177e4SLinus Torvalds if (!open->op_truncate) 47951da177e4SLinus Torvalds return 0; 47961da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 47979246585aSAl Viro return nfserr_inval; 47982a1aa489SArnd Bergmann return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0); 47991da177e4SLinus Torvalds } 48001da177e4SLinus Torvalds 48017e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 48026eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 48036eb3a1d0SJeff Layton struct nfsd4_open *open) 48047e6a72e5SChristoph Hellwig { 4805fd4f83fdSJeff Layton struct nfsd_file *nf = NULL; 48067e6a72e5SChristoph Hellwig __be32 status; 48077e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 48087e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 4809baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 48107e6a72e5SChristoph Hellwig 4811de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4812baeb4ff0SJeff Layton 4813baeb4ff0SJeff Layton /* 4814baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 4815baeb4ff0SJeff Layton * current access? 4816baeb4ff0SJeff Layton */ 4817baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4818baeb4ff0SJeff Layton if (status != nfs_ok) { 4819baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4820baeb4ff0SJeff Layton goto out; 4821baeb4ff0SJeff Layton } 4822baeb4ff0SJeff Layton 4823baeb4ff0SJeff Layton /* set access to the file */ 4824baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 4825baeb4ff0SJeff Layton if (status != nfs_ok) { 4826baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4827baeb4ff0SJeff Layton goto out; 4828baeb4ff0SJeff Layton } 4829baeb4ff0SJeff Layton 4830baeb4ff0SJeff Layton /* Set access bits in stateid */ 4831baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 4832baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 4833baeb4ff0SJeff Layton 4834baeb4ff0SJeff Layton /* Set new deny mask */ 4835baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 4836baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4837baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 4838baeb4ff0SJeff Layton 48397e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 4840de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4841fd4f83fdSJeff Layton status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); 48427e6a72e5SChristoph Hellwig if (status) 4843baeb4ff0SJeff Layton goto out_put_access; 4844de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4845de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 4846fd4f83fdSJeff Layton fp->fi_fds[oflag] = nf; 4847fd4f83fdSJeff Layton nf = NULL; 4848de18643dSTrond Myklebust } 48497e6a72e5SChristoph Hellwig } 4850de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4851fd4f83fdSJeff Layton if (nf) 4852fd4f83fdSJeff Layton nfsd_file_put(nf); 48537e6a72e5SChristoph Hellwig 48547e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 48557e6a72e5SChristoph Hellwig if (status) 48567e6a72e5SChristoph Hellwig goto out_put_access; 48577e6a72e5SChristoph Hellwig out: 48587e6a72e5SChristoph Hellwig return status; 4859baeb4ff0SJeff Layton out_put_access: 4860baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 4861baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 4862baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 4863baeb4ff0SJeff Layton goto out; 48647e6a72e5SChristoph Hellwig } 48657e6a72e5SChristoph Hellwig 4866b37ad28bSAl Viro static __be32 4867dcef0413SJ. 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) 48681da177e4SLinus Torvalds { 4869b37ad28bSAl Viro __be32 status; 48706ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 48711da177e4SLinus Torvalds 48726eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 4873baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 48747e6a72e5SChristoph Hellwig 4875baeb4ff0SJeff Layton /* test and set deny mode */ 4876baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 4877baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4878baeb4ff0SJeff Layton if (status == nfs_ok) { 4879baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4880baeb4ff0SJeff Layton fp->fi_share_deny |= 4881baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 48821da177e4SLinus Torvalds } 4883baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 48841da177e4SLinus Torvalds 4885baeb4ff0SJeff Layton if (status != nfs_ok) 4886baeb4ff0SJeff Layton return status; 4887baeb4ff0SJeff Layton 4888baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 4889baeb4ff0SJeff Layton if (status != nfs_ok) 4890baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 4891baeb4ff0SJeff Layton return status; 4892baeb4ff0SJeff Layton } 48931da177e4SLinus Torvalds 489414a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 489514a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 489614a24e99SJ. Bruce Fields { 489714a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 489814a24e99SJ. Bruce Fields return true; 489914a24e99SJ. Bruce Fields /* 490014a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 490114a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 490214a24e99SJ. Bruce Fields * until we hear otherwise: 490314a24e99SJ. Bruce Fields */ 490414a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 490514a24e99SJ. Bruce Fields } 490614a24e99SJ. Bruce Fields 4907653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 4908653e514eSJ. Bruce Fields int flag) 490922d38c4cSJ. Bruce Fields { 491022d38c4cSJ. Bruce Fields struct file_lock *fl; 491122d38c4cSJ. Bruce Fields 491222d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 491322d38c4cSJ. Bruce Fields if (!fl) 491422d38c4cSJ. Bruce Fields return NULL; 491522d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 4916617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 491722d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 491822d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 4919653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 492022d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 4921eb82dd39SJeff Layton fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; 492222d38c4cSJ. Bruce Fields return fl; 492322d38c4cSJ. Bruce Fields } 492422d38c4cSJ. Bruce Fields 49250b26693cSJeff Layton static struct nfs4_delegation * 49260b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 49278287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 4928acfdf5c3SJ. Bruce Fields { 492968b18f52SJ. Bruce Fields int status = 0; 49300b26693cSJeff Layton struct nfs4_delegation *dp; 4931eb82dd39SJeff Layton struct nfsd_file *nf; 4932353601e7SJ. Bruce Fields struct file_lock *fl; 4933417c6629SJeff Layton 4934353601e7SJ. Bruce Fields /* 4935353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 4936353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 4937353601e7SJ. Bruce Fields * the end: 4938353601e7SJ. Bruce Fields */ 4939bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 49400b26693cSJeff Layton return ERR_PTR(-EAGAIN); 49410b26693cSJeff Layton 4942eb82dd39SJeff Layton nf = find_readable_file(fp); 4943eb82dd39SJeff Layton if (!nf) { 4944353601e7SJ. Bruce Fields /* We should always have a readable file here */ 4945353601e7SJ. Bruce Fields WARN_ON_ONCE(1); 4946353601e7SJ. Bruce Fields return ERR_PTR(-EBADF); 4947353601e7SJ. Bruce Fields } 494834ed9872SAndrew Elble spin_lock(&state_lock); 494934ed9872SAndrew Elble spin_lock(&fp->fi_lock); 495068b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 495168b18f52SJ. Bruce Fields status = -EAGAIN; 4952353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 4953eb82dd39SJeff Layton fp->fi_deleg_file = nf; 4954353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 4955353601e7SJ. Bruce Fields * cleared */ 4956353601e7SJ. Bruce Fields fp->fi_delegees = 1; 4957eb82dd39SJeff Layton nf = NULL; 4958353601e7SJ. Bruce Fields } else 4959353601e7SJ. Bruce Fields fp->fi_delegees++; 4960353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 4961353601e7SJ. Bruce Fields spin_unlock(&state_lock); 4962eb82dd39SJeff Layton if (nf) 4963eb82dd39SJeff Layton nfsd_file_put(nf); 4964353601e7SJ. Bruce Fields if (status) 4965353601e7SJ. Bruce Fields return ERR_PTR(status); 4966353601e7SJ. Bruce Fields 4967353601e7SJ. Bruce Fields status = -ENOMEM; 4968353601e7SJ. Bruce Fields dp = alloc_init_deleg(clp, fp, fh, odstate); 4969353601e7SJ. Bruce Fields if (!dp) 4970353601e7SJ. Bruce Fields goto out_delegees; 4971353601e7SJ. Bruce Fields 4972353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 4973353601e7SJ. Bruce Fields if (!fl) 4974bd8d7250SAndrew Elble goto out_clnt_odstate; 4975353601e7SJ. Bruce Fields 4976eb82dd39SJeff Layton status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); 4977353601e7SJ. Bruce Fields if (fl) 4978353601e7SJ. Bruce Fields locks_free_lock(fl); 4979353601e7SJ. Bruce Fields if (status) 4980353601e7SJ. Bruce Fields goto out_clnt_odstate; 4981353601e7SJ. Bruce Fields 4982353601e7SJ. Bruce Fields spin_lock(&state_lock); 4983353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 4984353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 4985353601e7SJ. Bruce Fields status = -EAGAIN; 4986353601e7SJ. Bruce Fields else 4987353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 498834ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 498934ed9872SAndrew Elble spin_unlock(&state_lock); 499034ed9872SAndrew Elble 499134ed9872SAndrew Elble if (status) 4992692ad280SAndrew Elble goto out_unlock; 4993692ad280SAndrew Elble 49940b26693cSJeff Layton return dp; 4995692ad280SAndrew Elble out_unlock: 4996eb82dd39SJeff Layton vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); 4997353601e7SJ. Bruce Fields out_clnt_odstate: 4998353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 4999353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 5000353601e7SJ. Bruce Fields out_delegees: 5001353601e7SJ. Bruce Fields put_deleg_file(fp); 5002353601e7SJ. Bruce Fields return ERR_PTR(status); 5003edab9782SJ. Bruce Fields } 5004edab9782SJ. Bruce Fields 50054aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 50064aa8913cSBenny Halevy { 50074aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 50084aa8913cSBenny Halevy if (status == -EAGAIN) 50094aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 50104aa8913cSBenny Halevy else { 50114aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 50124aa8913cSBenny Halevy switch (open->op_deleg_want) { 50134aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 50144aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 50154aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 50164aa8913cSBenny Halevy break; 50174aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 50184aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 50194aa8913cSBenny Halevy break; 50204aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 5021063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 50224aa8913cSBenny Halevy } 50234aa8913cSBenny Halevy } 50244aa8913cSBenny Halevy } 50254aa8913cSBenny Halevy 50261da177e4SLinus Torvalds /* 50271da177e4SLinus Torvalds * Attempt to hand out a delegation. 502899c41515SJ. Bruce Fields * 502999c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 503099c41515SJ. Bruce Fields * proper support for them. 50311da177e4SLinus Torvalds */ 50321da177e4SLinus Torvalds static void 50334cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 50344cf59221SJeff Layton struct nfs4_ol_stateid *stp) 50351da177e4SLinus Torvalds { 50361da177e4SLinus Torvalds struct nfs4_delegation *dp; 50374cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 50384cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 503914a24e99SJ. Bruce Fields int cb_up; 504099c41515SJ. Bruce Fields int status = 0; 50411da177e4SLinus Torvalds 5042fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 50437b190fecSNeilBrown open->op_recall = 0; 50447b190fecSNeilBrown switch (open->op_claim_type) { 50457b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 50462bf23875SJ. Bruce Fields if (!cb_up) 50477b190fecSNeilBrown open->op_recall = 1; 504899c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 504999c41515SJ. Bruce Fields goto out_no_deleg; 50507b190fecSNeilBrown break; 50517b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 5052ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 505399c41515SJ. Bruce Fields /* 505499c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 5055c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 5056c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 505799c41515SJ. Bruce Fields */ 50584cf59221SJeff Layton if (locks_in_grace(clp->net)) 505999c41515SJ. Bruce Fields goto out_no_deleg; 5060dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 506199c41515SJ. Bruce Fields goto out_no_deleg; 50629a0590aeSSteve Dickson /* 50639a0590aeSSteve Dickson * Also, if the file was opened for write or 50649a0590aeSSteve Dickson * create, there's a good chance the client's 50659a0590aeSSteve Dickson * about to write to it, resulting in an 50669a0590aeSSteve Dickson * immediate recall (since we don't support 50679a0590aeSSteve Dickson * write delegations): 50689a0590aeSSteve Dickson */ 50691da177e4SLinus Torvalds if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) 507099c41515SJ. Bruce Fields goto out_no_deleg; 507199c41515SJ. Bruce Fields if (open->op_create == NFS4_OPEN_CREATE) 507299c41515SJ. Bruce Fields goto out_no_deleg; 50737b190fecSNeilBrown break; 50747b190fecSNeilBrown default: 507599c41515SJ. Bruce Fields goto out_no_deleg; 50767b190fecSNeilBrown } 50778287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 50780b26693cSJeff Layton if (IS_ERR(dp)) 5079dd239cc0SJ. Bruce Fields goto out_no_deleg; 50801da177e4SLinus Torvalds 5081d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 50821da177e4SLinus Torvalds 5083dd5e3fbcSChuck Lever trace_nfsd_deleg_open(&dp->dl_stid.sc_stateid); 508499c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 508567cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5086dd239cc0SJ. Bruce Fields return; 5087dd239cc0SJ. Bruce Fields out_no_deleg: 508899c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 50897b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 5090d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 50911da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 5092d08d32e6SJ. Bruce Fields open->op_recall = 1; 5093d08d32e6SJ. Bruce Fields } 5094dd239cc0SJ. Bruce Fields 5095dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 5096dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 5097dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 5098dd239cc0SJ. Bruce Fields return; 50991da177e4SLinus Torvalds } 51001da177e4SLinus Torvalds 5101e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 5102e27f49c3SBenny Halevy struct nfs4_delegation *dp) 5103e27f49c3SBenny Halevy { 5104e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 5105e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5106e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5107e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 5108e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 5109e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5110e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5111e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 5112e27f49c3SBenny Halevy } 5113e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 5114e27f49c3SBenny Halevy * it already has, therefore we don't return 5115e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 5116e27f49c3SBenny Halevy */ 5117e27f49c3SBenny Halevy } 5118e27f49c3SBenny Halevy 5119b37ad28bSAl Viro __be32 51201da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 51211da177e4SLinus Torvalds { 51226668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 512338c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 51241da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 5125dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 5126567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 5127b37ad28bSAl Viro __be32 status; 5128d8a1a000STrond Myklebust bool new_stp = false; 51291da177e4SLinus Torvalds 51301da177e4SLinus Torvalds /* 51311da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 51321da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 51331da177e4SLinus Torvalds * If not found, create the nfs4_file struct 51341da177e4SLinus Torvalds */ 5135f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 5136950e0118STrond Myklebust if (fp != open->op_file) { 513741d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 5138c44c5eebSNeilBrown if (status) 5139c44c5eebSNeilBrown goto out; 514015ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 51411da177e4SLinus Torvalds } else { 5142950e0118STrond Myklebust open->op_file = NULL; 5143c44c5eebSNeilBrown status = nfserr_bad_stateid; 51448b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 5145c44c5eebSNeilBrown goto out; 51461da177e4SLinus Torvalds } 51471da177e4SLinus Torvalds 5148d8a1a000STrond Myklebust if (!stp) { 5149d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 5150d8a1a000STrond Myklebust if (!open->op_stp) 5151d8a1a000STrond Myklebust new_stp = true; 5152d8a1a000STrond Myklebust } 5153d8a1a000STrond Myklebust 51541da177e4SLinus Torvalds /* 51551da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 51561da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 5157d8a1a000STrond Myklebust * 5158d8a1a000STrond Myklebust * stp is already locked. 51591da177e4SLinus Torvalds */ 5160d8a1a000STrond Myklebust if (!new_stp) { 51611da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 5162f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 516335a92fe8SJeff Layton if (status) { 5164feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 51651da177e4SLinus Torvalds goto out; 516635a92fe8SJeff Layton } 51671da177e4SLinus Torvalds } else { 51686eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 51696eb3a1d0SJeff Layton if (status) { 5170d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 51716eb3a1d0SJeff Layton release_open_stateid(stp); 5172d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 51736eb3a1d0SJeff Layton goto out; 51746eb3a1d0SJeff Layton } 51758287f009SSachin Bhamare 51768287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 51778287f009SSachin Bhamare open->op_odstate); 51788287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 51798287f009SSachin Bhamare open->op_odstate = NULL; 51801da177e4SLinus Torvalds } 5181d8a1a000STrond Myklebust 51829767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 5183feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 51841da177e4SLinus Torvalds 5185d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 5186d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 5187d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5188d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 5189d24433cdSBenny Halevy goto nodeleg; 5190d24433cdSBenny Halevy } 5191d24433cdSBenny Halevy } 5192d24433cdSBenny Halevy 51931da177e4SLinus Torvalds /* 51941da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 51951da177e4SLinus Torvalds * OPEN succeeds even if we fail. 51961da177e4SLinus Torvalds */ 51974cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 5198d24433cdSBenny Halevy nodeleg: 51991da177e4SLinus Torvalds status = nfs_ok; 5200dd5e3fbcSChuck Lever trace_nfsd_deleg_none(&stp->st_stid.sc_stateid); 52011da177e4SLinus Torvalds out: 5202d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 5203d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 5204e27f49c3SBenny Halevy open->op_deleg_want) 5205e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 5206d24433cdSBenny Halevy 520713cd2184SNeilBrown if (fp) 520813cd2184SNeilBrown put_nfs4_file(fp); 520937515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 521087186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 52111da177e4SLinus Torvalds /* 52121da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 52131da177e4SLinus Torvalds */ 52141da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 521519e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 521619e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 521719e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 52181da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 521919e4c347SJeff Layton 5220dcd94cc2STrond Myklebust if (dp) 5221dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5222d6f2bc5dSTrond Myklebust if (stp) 5223d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 52241da177e4SLinus Torvalds 52251da177e4SLinus Torvalds return status; 52261da177e4SLinus Torvalds } 52271da177e4SLinus Torvalds 522858fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 522942297899SJeff Layton struct nfsd4_open *open) 5230d29b20cdSJ. Bruce Fields { 5231d29b20cdSJ. Bruce Fields if (open->op_openowner) { 5232d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 5233d29b20cdSJ. Bruce Fields 5234d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 5235d3134b10SJeff Layton nfs4_put_stateowner(so); 5236d29b20cdSJ. Bruce Fields } 523732513b40SJ. Bruce Fields if (open->op_file) 52385b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 52394cdc951bSJ. Bruce Fields if (open->op_stp) 52406011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 52418287f009SSachin Bhamare if (open->op_odstate) 52428287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 5243d29b20cdSJ. Bruce Fields } 5244d29b20cdSJ. Bruce Fields 5245b37ad28bSAl Viro __be32 5246b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5247eb69853dSChristoph Hellwig union nfsd4_op_u *u) 52481da177e4SLinus Torvalds { 5249eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 52501da177e4SLinus Torvalds struct nfs4_client *clp; 5251b37ad28bSAl Viro __be32 status; 52527f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 52531da177e4SLinus Torvalds 5254dd5e3fbcSChuck Lever trace_nfsd_clid_renew(clid); 5255b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 52569b2ef62bSJ. Bruce Fields if (status) 52571da177e4SLinus Torvalds goto out; 52584b24ca7dSJeff Layton clp = cstate->clp; 52591da177e4SLinus Torvalds status = nfserr_cb_path_down; 5260ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 526177a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 52621da177e4SLinus Torvalds goto out; 52631da177e4SLinus Torvalds status = nfs_ok; 52641da177e4SLinus Torvalds out: 52651da177e4SLinus Torvalds return status; 52661da177e4SLinus Torvalds } 52671da177e4SLinus Torvalds 52687f5ef2e9SJeff Layton void 526912760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 5270a76b4319SNeilBrown { 527133dcc481SJeff Layton /* do nothing if grace period already ended */ 5272a51c84edSStanislav Kinsbursky if (nn->grace_ended) 527333dcc481SJeff Layton return; 527433dcc481SJeff Layton 5275dd5e3fbcSChuck Lever trace_nfsd_grace_complete(nn); 5276a51c84edSStanislav Kinsbursky nn->grace_ended = true; 527770b28235SJ. Bruce Fields /* 527870b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 527970b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 528070b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 528170b28235SJ. Bruce Fields * 528270b28235SJ. Bruce Fields */ 5283919b8049SJeff Layton nfsd4_record_grace_done(nn); 528470b28235SJ. Bruce Fields /* 528570b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 528670b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 528770b28235SJ. Bruce Fields * of luck on the next boot. 528870b28235SJ. Bruce Fields * 528970b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 529070b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 529170b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 529270b28235SJ. Bruce Fields */ 52935e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 529470b28235SJ. Bruce Fields /* 529570b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 529670b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 529770b28235SJ. Bruce Fields * regular locking can resume. 529870b28235SJ. Bruce Fields */ 5299a76b4319SNeilBrown } 5300a76b4319SNeilBrown 530103f318caSJ. Bruce Fields /* 530203f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 530303f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 530403f318caSJ. Bruce Fields */ 530503f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 530603f318caSJ. Bruce Fields { 530720b7d86fSArnd Bergmann time64_t double_grace_period_end = nn->boot_time + 530820b7d86fSArnd Bergmann 2 * nn->nfsd4_lease; 530903f318caSJ. Bruce Fields 5310362063a5SScott Mayhew if (nn->track_reclaim_completes && 5311362063a5SScott Mayhew atomic_read(&nn->nr_reclaim_complete) == 5312362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) 5313362063a5SScott Mayhew return false; 531403f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 531503f318caSJ. Bruce Fields return false; 531603f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 531703f318caSJ. Bruce Fields /* 531803f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 531903f318caSJ. Bruce Fields * still not done, give up: 532003f318caSJ. Bruce Fields */ 532120b7d86fSArnd Bergmann if (ktime_get_boottime_seconds() > double_grace_period_end) 532203f318caSJ. Bruce Fields return false; 532303f318caSJ. Bruce Fields return true; 532403f318caSJ. Bruce Fields } 532503f318caSJ. Bruce Fields 532620b7d86fSArnd Bergmann static time64_t 532709121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 53281da177e4SLinus Torvalds { 53291da177e4SLinus Torvalds struct nfs4_client *clp; 5330fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 53311da177e4SLinus Torvalds struct nfs4_delegation *dp; 5332217526e7SJeff Layton struct nfs4_ol_stateid *stp; 53337919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 53341da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 533520b7d86fSArnd Bergmann time64_t cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease; 533620b7d86fSArnd Bergmann time64_t t, new_timeo = nn->nfsd4_lease; 5337624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 5338624322f1SOlga Kornievskaia copy_stateid_t *cps_t; 5339624322f1SOlga Kornievskaia int i; 53401da177e4SLinus Torvalds 534103f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 534203f318caSJ. Bruce Fields new_timeo = 0; 534303f318caSJ. Bruce Fields goto out; 534403f318caSJ. Bruce Fields } 534512760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 534636acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 5347624322f1SOlga Kornievskaia 5348624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5349624322f1SOlga Kornievskaia idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { 5350624322f1SOlga Kornievskaia cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); 5351624322f1SOlga Kornievskaia if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID && 535220b7d86fSArnd Bergmann cps->cpntf_time > cutoff) 5353624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 5354624322f1SOlga Kornievskaia } 5355624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5356624322f1SOlga Kornievskaia 5357c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 53585ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 53591da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 536020b7d86fSArnd Bergmann if (clp->cl_time > cutoff) { 53611da177e4SLinus Torvalds t = clp->cl_time - cutoff; 5362a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 53631da177e4SLinus Torvalds break; 53641da177e4SLinus Torvalds } 5365221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 5366dd5e3fbcSChuck Lever trace_nfsd_clid_expired(&clp->cl_clientid); 5367d7682988SBenny Halevy continue; 5368d7682988SBenny Halevy } 53694864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 537036acb66bSBenny Halevy } 5371c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 537236acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 537336acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 5374dd5e3fbcSChuck Lever trace_nfsd_clid_purged(&clp->cl_clientid); 53754864af97STrond Myklebust list_del_init(&clp->cl_lru); 53761da177e4SLinus Torvalds expire_client(clp); 53771da177e4SLinus Torvalds } 5378cdc97505SBenny Halevy spin_lock(&state_lock); 5379e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 53801da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 538120b7d86fSArnd Bergmann if (dp->dl_time > cutoff) { 5382a832e7aeSJeff Layton t = dp->dl_time - cutoff; 5383a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 53841da177e4SLinus Torvalds break; 53851da177e4SLinus Torvalds } 53863fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 538742690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 53881da177e4SLinus Torvalds } 5389cdc97505SBenny Halevy spin_unlock(&state_lock); 53902d4a532dSJeff Layton while (!list_empty(&reaplist)) { 53912d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 53922d4a532dSJeff Layton dl_recall_lru); 53932d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 53943bd64a5bSJ. Bruce Fields revoke_delegation(dp); 53951da177e4SLinus Torvalds } 5396217526e7SJeff Layton 5397217526e7SJeff Layton spin_lock(&nn->client_lock); 5398217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 5399217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 5400217526e7SJeff Layton oo_close_lru); 540120b7d86fSArnd Bergmann if (oo->oo_time > cutoff) { 5402a832e7aeSJeff Layton t = oo->oo_time - cutoff; 5403a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 54041da177e4SLinus Torvalds break; 54051da177e4SLinus Torvalds } 5406217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 5407217526e7SJeff Layton stp = oo->oo_last_closed_stid; 5408217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 5409217526e7SJeff Layton spin_unlock(&nn->client_lock); 5410217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 5411217526e7SJeff Layton spin_lock(&nn->client_lock); 54121da177e4SLinus Torvalds } 5413217526e7SJeff Layton spin_unlock(&nn->client_lock); 5414217526e7SJeff Layton 54157919d0a2SJeff Layton /* 54167919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 54177919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 54187919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 54197919d0a2SJeff Layton * under the assumption that the client is no longer interested. 54207919d0a2SJeff Layton * 54217919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 54227919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 54237919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 54247919d0a2SJeff Layton * indefinitely once the lock does become free. 54257919d0a2SJeff Layton */ 54267919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 54270cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 54287919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 54297919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 54307919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 543120b7d86fSArnd Bergmann if (nbl->nbl_time > cutoff) { 54327919d0a2SJeff Layton t = nbl->nbl_time - cutoff; 54337919d0a2SJeff Layton new_timeo = min(new_timeo, t); 54347919d0a2SJeff Layton break; 54357919d0a2SJeff Layton } 54367919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 54377919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 54387919d0a2SJeff Layton } 54390cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 54407919d0a2SJeff Layton 54417919d0a2SJeff Layton while (!list_empty(&reaplist)) { 544264ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 54437919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 54447919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 54457919d0a2SJeff Layton free_blocked_lock(nbl); 54467919d0a2SJeff Layton } 544703f318caSJ. Bruce Fields out: 544820b7d86fSArnd Bergmann new_timeo = max_t(time64_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 5449a832e7aeSJeff Layton return new_timeo; 54501da177e4SLinus Torvalds } 54511da177e4SLinus Torvalds 5452a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 5453a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 5454a254b246SHarvey Harrison 5455a254b246SHarvey Harrison static void 545609121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 54571da177e4SLinus Torvalds { 545820b7d86fSArnd Bergmann time64_t t; 54592e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 546009121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 546109121281SStanislav Kinsbursky laundromat_work); 54621da177e4SLinus Torvalds 546309121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 546409121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 54651da177e4SLinus Torvalds } 54661da177e4SLinus Torvalds 54678fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 5468f8816512SNeilBrown { 54698fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 5470f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 5471f7a4d872SJ. Bruce Fields return nfs_ok; 54721da177e4SLinus Torvalds } 54731da177e4SLinus Torvalds 54741da177e4SLinus Torvalds static inline int 547582c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 54761da177e4SLinus Torvalds { 547782c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 547882c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 547982c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 54801da177e4SLinus Torvalds } 54811da177e4SLinus Torvalds 54821da177e4SLinus Torvalds static inline int 548382c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 54841da177e4SLinus Torvalds { 548582c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 548682c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 54871da177e4SLinus Torvalds } 54881da177e4SLinus Torvalds 54891da177e4SLinus Torvalds static 5490dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 54911da177e4SLinus Torvalds { 5492b37ad28bSAl Viro __be32 status = nfserr_openmode; 54931da177e4SLinus Torvalds 549402921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 549502921914SJ. Bruce Fields if (stp->st_openstp) 549602921914SJ. Bruce Fields stp = stp->st_openstp; 549782c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 54981da177e4SLinus Torvalds goto out; 549982c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 55001da177e4SLinus Torvalds goto out; 55011da177e4SLinus Torvalds status = nfs_ok; 55021da177e4SLinus Torvalds out: 55031da177e4SLinus Torvalds return status; 55041da177e4SLinus Torvalds } 55051da177e4SLinus Torvalds 5506b37ad28bSAl Viro static inline __be32 55075ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 55081da177e4SLinus Torvalds { 5509203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 55101da177e4SLinus Torvalds return nfs_ok; 5511c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 551225985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 55131da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 55141da177e4SLinus Torvalds return nfserr_grace; 55151da177e4SLinus Torvalds } else if (flags & WR_STATE) 55161da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 55171da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 55181da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 55191da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 55201da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 55211da177e4SLinus Torvalds } 55221da177e4SLinus Torvalds 55231da177e4SLinus Torvalds /* 55241da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 55251da177e4SLinus Torvalds * that are not able to provide mandatory locking. 55261da177e4SLinus Torvalds */ 55271da177e4SLinus Torvalds static inline int 55285ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 55291da177e4SLinus Torvalds { 5530c87fb4a3SJ. Bruce Fields return opens_in_grace(net) && mandatory_lock(inode); 55311da177e4SLinus Torvalds } 55321da177e4SLinus Torvalds 553357b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 55340836f587SJ. Bruce Fields { 55356668958fSAndy Adamson /* 55366668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 55376668958fSAndy Adamson * when it is zero. 55386668958fSAndy Adamson */ 553928dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 554081b82965SJ. Bruce Fields return nfs_ok; 554181b82965SJ. Bruce Fields 554281b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 554381b82965SJ. Bruce Fields return nfs_ok; 55446668958fSAndy Adamson 55450836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 554614b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 55470836f587SJ. Bruce Fields return nfserr_bad_stateid; 55480836f587SJ. Bruce Fields /* 554981b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 555081b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 555181b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 555281b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 555381b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 555481b82965SJ. Bruce Fields * but better performance may result in retrying IO that 555581b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 555681b82965SJ. Bruce Fields * reordered in flight: 55570836f587SJ. Bruce Fields */ 55580836f587SJ. Bruce Fields return nfserr_old_stateid; 55590836f587SJ. Bruce Fields } 55600836f587SJ. Bruce Fields 556103da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 556203da3169STrond Myklebust { 556303da3169STrond Myklebust __be32 ret; 556403da3169STrond Myklebust 556503da3169STrond Myklebust spin_lock(&s->sc_lock); 556603da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 556703da3169STrond Myklebust if (ret == nfs_ok) 556803da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 556903da3169STrond Myklebust spin_unlock(&s->sc_lock); 557003da3169STrond Myklebust return ret; 557103da3169STrond Myklebust } 557203da3169STrond Myklebust 5573ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 5574ebe9cb3bSChristoph Hellwig { 5575ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 5576ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 5577ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 5578ebe9cb3bSChristoph Hellwig return nfs_ok; 5579ebe9cb3bSChristoph Hellwig } 5580ebe9cb3bSChristoph Hellwig 55817df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 558217456804SBryan Schumaker { 558397b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 55841af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 558517456804SBryan Schumaker 5586ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5587ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 55881af71cc8SJeff Layton return status; 5589663e36f0SJ. Bruce Fields if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) 55901af71cc8SJeff Layton return status; 55911af71cc8SJeff Layton spin_lock(&cl->cl_lock); 55921af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 559397b7e3b6SJ. Bruce Fields if (!s) 55941af71cc8SJeff Layton goto out_unlock; 559503da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 559617456804SBryan Schumaker if (status) 55971af71cc8SJeff Layton goto out_unlock; 559823340032SJ. Bruce Fields switch (s->sc_type) { 559923340032SJ. Bruce Fields case NFS4_DELEG_STID: 56001af71cc8SJeff Layton status = nfs_ok; 56011af71cc8SJeff Layton break; 56023bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 56031af71cc8SJeff Layton status = nfserr_deleg_revoked; 56041af71cc8SJeff Layton break; 560523340032SJ. Bruce Fields case NFS4_OPEN_STID: 560623340032SJ. Bruce Fields case NFS4_LOCK_STID: 5607ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 56081af71cc8SJeff Layton break; 560923340032SJ. Bruce Fields default: 561023340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 5611b0fc29d6STrond Myklebust /* Fallthrough */ 561223340032SJ. Bruce Fields case NFS4_CLOSED_STID: 5613b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 56141af71cc8SJeff Layton status = nfserr_bad_stateid; 561523340032SJ. Bruce Fields } 56161af71cc8SJeff Layton out_unlock: 56171af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 56181af71cc8SJeff Layton return status; 561917456804SBryan Schumaker } 562017456804SBryan Schumaker 5621cd61c522SChristoph Hellwig __be32 56222dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 56232dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 56242dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 562538c2f4b1SJ. Bruce Fields { 56260eb6f20aSJ. Bruce Fields __be32 status; 562795da1b3aSAndrew Elble bool return_revoked = false; 562895da1b3aSAndrew Elble 562995da1b3aSAndrew Elble /* 563095da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 563195da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 563295da1b3aSAndrew Elble */ 563395da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 563495da1b3aSAndrew Elble return_revoked = true; 563595da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 563695da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 563738c2f4b1SJ. Bruce Fields 5638ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5639ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 564038c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 5641b7342204SOlga Kornievskaia status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn, 5642b7342204SOlga Kornievskaia false); 5643a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 56444b24ca7dSJeff Layton if (cstate->session) 5645a8a7c677STrond Myklebust return nfserr_bad_stateid; 564638c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 5647a8a7c677STrond Myklebust } 56480eb6f20aSJ. Bruce Fields if (status) 56490eb6f20aSJ. Bruce Fields return status; 56504b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 565138c2f4b1SJ. Bruce Fields if (!*s) 565238c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 565395da1b3aSAndrew Elble if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 565495da1b3aSAndrew Elble nfs4_put_stid(*s); 565595da1b3aSAndrew Elble if (cstate->minorversion) 565695da1b3aSAndrew Elble return nfserr_deleg_revoked; 565795da1b3aSAndrew Elble return nfserr_bad_stateid; 565895da1b3aSAndrew Elble } 565938c2f4b1SJ. Bruce Fields return nfs_ok; 566038c2f4b1SJ. Bruce Fields } 566138c2f4b1SJ. Bruce Fields 5662eb82dd39SJeff Layton static struct nfsd_file * 5663a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 5664a0649b2dSChristoph Hellwig { 5665af90f707SChristoph Hellwig if (!s) 5666af90f707SChristoph Hellwig return NULL; 5667af90f707SChristoph Hellwig 5668a0649b2dSChristoph Hellwig switch (s->sc_type) { 5669a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 5670a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 5671a0649b2dSChristoph Hellwig return NULL; 5672eb82dd39SJeff Layton return nfsd_file_get(s->sc_file->fi_deleg_file); 5673a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 5674a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 5675a0649b2dSChristoph Hellwig if (flags & RD_STATE) 5676a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 5677a0649b2dSChristoph Hellwig else 5678a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 5679a0649b2dSChristoph Hellwig break; 5680a0649b2dSChristoph Hellwig } 5681a0649b2dSChristoph Hellwig 5682a0649b2dSChristoph Hellwig return NULL; 5683a0649b2dSChristoph Hellwig } 5684a0649b2dSChristoph Hellwig 5685a0649b2dSChristoph Hellwig static __be32 5686d8836f77SJ. Bruce Fields nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) 5687a0649b2dSChristoph Hellwig { 5688a0649b2dSChristoph Hellwig __be32 status; 5689a0649b2dSChristoph Hellwig 5690a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 5691a0649b2dSChristoph Hellwig if (status) 5692a0649b2dSChristoph Hellwig return status; 5693a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 5694a0649b2dSChristoph Hellwig } 5695a0649b2dSChristoph Hellwig 5696af90f707SChristoph Hellwig static __be32 5697af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 56985c4583b2SJeff Layton struct nfsd_file **nfp, int flags) 5699af90f707SChristoph Hellwig { 5700af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 5701eb82dd39SJeff Layton struct nfsd_file *nf; 5702af90f707SChristoph Hellwig __be32 status; 5703af90f707SChristoph Hellwig 5704eb82dd39SJeff Layton nf = nfs4_find_file(s, flags); 5705eb82dd39SJeff Layton if (nf) { 5706af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 5707af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 57085c4583b2SJeff Layton if (status) { 57095c4583b2SJeff Layton nfsd_file_put(nf); 5710eb82dd39SJeff Layton goto out; 57115c4583b2SJeff Layton } 5712af90f707SChristoph Hellwig } else { 5713eb82dd39SJeff Layton status = nfsd_file_acquire(rqstp, fhp, acc, &nf); 5714af90f707SChristoph Hellwig if (status) 5715af90f707SChristoph Hellwig return status; 5716af90f707SChristoph Hellwig } 57175c4583b2SJeff Layton *nfp = nf; 5718eb82dd39SJeff Layton out: 5719eb82dd39SJeff Layton return status; 5720af90f707SChristoph Hellwig } 5721624322f1SOlga Kornievskaia static void 5722624322f1SOlga Kornievskaia _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 5723624322f1SOlga Kornievskaia { 5724624322f1SOlga Kornievskaia WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID); 5725624322f1SOlga Kornievskaia if (!refcount_dec_and_test(&cps->cp_stateid.sc_count)) 5726624322f1SOlga Kornievskaia return; 5727624322f1SOlga Kornievskaia list_del(&cps->cp_list); 5728624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 5729624322f1SOlga Kornievskaia cps->cp_stateid.stid.si_opaque.so_id); 5730624322f1SOlga Kornievskaia kfree(cps); 5731624322f1SOlga Kornievskaia } 5732b7342204SOlga Kornievskaia /* 5733b7342204SOlga Kornievskaia * A READ from an inter server to server COPY will have a 5734b7342204SOlga Kornievskaia * copy stateid. Look up the copy notify stateid from the 5735b7342204SOlga Kornievskaia * idr structure and take a reference on it. 5736b7342204SOlga Kornievskaia */ 5737ce0887acSOlga Kornievskaia __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st, 5738ce0887acSOlga Kornievskaia struct nfs4_client *clp, 5739b7342204SOlga Kornievskaia struct nfs4_cpntf_state **cps) 5740b7342204SOlga Kornievskaia { 5741b7342204SOlga Kornievskaia copy_stateid_t *cps_t; 5742b7342204SOlga Kornievskaia struct nfs4_cpntf_state *state = NULL; 5743b7342204SOlga Kornievskaia 5744b7342204SOlga Kornievskaia if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id) 5745b7342204SOlga Kornievskaia return nfserr_bad_stateid; 5746b7342204SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5747b7342204SOlga Kornievskaia cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id); 5748b7342204SOlga Kornievskaia if (cps_t) { 5749b7342204SOlga Kornievskaia state = container_of(cps_t, struct nfs4_cpntf_state, 5750b7342204SOlga Kornievskaia cp_stateid); 57515277a79eSDan Carpenter if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID) { 57525277a79eSDan Carpenter state = NULL; 57535277a79eSDan Carpenter goto unlock; 57545277a79eSDan Carpenter } 5755ce0887acSOlga Kornievskaia if (!clp) 5756b7342204SOlga Kornievskaia refcount_inc(&state->cp_stateid.sc_count); 5757ce0887acSOlga Kornievskaia else 5758ce0887acSOlga Kornievskaia _free_cpntf_state_locked(nn, state); 5759b7342204SOlga Kornievskaia } 57605277a79eSDan Carpenter unlock: 5761b7342204SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5762b7342204SOlga Kornievskaia if (!state) 5763b7342204SOlga Kornievskaia return nfserr_bad_stateid; 5764ce0887acSOlga Kornievskaia if (!clp && state) 5765b7342204SOlga Kornievskaia *cps = state; 5766b7342204SOlga Kornievskaia return 0; 5767b7342204SOlga Kornievskaia } 5768b7342204SOlga Kornievskaia 5769b7342204SOlga Kornievskaia static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, 5770b7342204SOlga Kornievskaia struct nfs4_stid **stid) 5771b7342204SOlga Kornievskaia { 5772b7342204SOlga Kornievskaia __be32 status; 5773b7342204SOlga Kornievskaia struct nfs4_cpntf_state *cps = NULL; 5774b7342204SOlga Kornievskaia struct nfsd4_compound_state cstate; 5775b7342204SOlga Kornievskaia 5776ce0887acSOlga Kornievskaia status = manage_cpntf_state(nn, st, NULL, &cps); 5777b7342204SOlga Kornievskaia if (status) 5778b7342204SOlga Kornievskaia return status; 5779b7342204SOlga Kornievskaia 578020b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 5781b7342204SOlga Kornievskaia memset(&cstate, 0, sizeof(cstate)); 5782b7342204SOlga Kornievskaia status = lookup_clientid(&cps->cp_p_clid, &cstate, nn, true); 5783b7342204SOlga Kornievskaia if (status) 5784b7342204SOlga Kornievskaia goto out; 5785b7342204SOlga Kornievskaia status = nfsd4_lookup_stateid(&cstate, &cps->cp_p_stateid, 5786b7342204SOlga Kornievskaia NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 5787b7342204SOlga Kornievskaia stid, nn); 5788b7342204SOlga Kornievskaia put_client_renew(cstate.clp); 5789b7342204SOlga Kornievskaia out: 5790b7342204SOlga Kornievskaia nfs4_put_cpntf_state(nn, cps); 5791b7342204SOlga Kornievskaia return status; 5792b7342204SOlga Kornievskaia } 5793624322f1SOlga Kornievskaia 5794624322f1SOlga Kornievskaia void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 5795624322f1SOlga Kornievskaia { 5796624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5797624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 5798624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5799624322f1SOlga Kornievskaia } 5800af90f707SChristoph Hellwig 58011da177e4SLinus Torvalds /* 58021da177e4SLinus Torvalds * Checks for stateid operations 58031da177e4SLinus Torvalds */ 5804b37ad28bSAl Viro __be32 5805af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 5806aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 5807624322f1SOlga Kornievskaia stateid_t *stateid, int flags, struct nfsd_file **nfp, 5808624322f1SOlga Kornievskaia struct nfs4_stid **cstid) 58091da177e4SLinus Torvalds { 5810a0649b2dSChristoph Hellwig struct inode *ino = d_inode(fhp->fh_dentry); 5811af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 58123320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5813af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 5814b37ad28bSAl Viro __be32 status; 58151da177e4SLinus Torvalds 58165c4583b2SJeff Layton if (nfp) 58175c4583b2SJeff Layton *nfp = NULL; 58181da177e4SLinus Torvalds 58195ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 58201da177e4SLinus Torvalds return nfserr_grace; 58211da177e4SLinus Torvalds 5822af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 5823af90f707SChristoph Hellwig status = check_special_stateids(net, fhp, stateid, flags); 5824af90f707SChristoph Hellwig goto done; 5825af90f707SChristoph Hellwig } 58261da177e4SLinus Torvalds 58272dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 5828db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 58292dd6e458STrond Myklebust &s, nn); 5830b7342204SOlga Kornievskaia if (status == nfserr_bad_stateid) 5831b7342204SOlga Kornievskaia status = find_cpntf_state(nn, stateid, &s); 583238c2f4b1SJ. Bruce Fields if (status) 5833c2d1d6a8STrond Myklebust return status; 583403da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 5835a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 58360c2a498fSJ. Bruce Fields if (status) 58370c2a498fSJ. Bruce Fields goto out; 5838a0649b2dSChristoph Hellwig 5839f7a4d872SJ. Bruce Fields switch (s->sc_type) { 5840f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 5841a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 5842f7a4d872SJ. Bruce Fields break; 5843f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 5844f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 5845d8836f77SJ. Bruce Fields status = nfs4_check_olstateid(openlockstateid(s), flags); 5846f7a4d872SJ. Bruce Fields break; 5847f7a4d872SJ. Bruce Fields default: 584814bcab1aSTrond Myklebust status = nfserr_bad_stateid; 5849a0649b2dSChristoph Hellwig break; 58501da177e4SLinus Torvalds } 58518fcd461dSJeff Layton if (status) 58528fcd461dSJeff Layton goto out; 58538fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 5854a0649b2dSChristoph Hellwig 5855af90f707SChristoph Hellwig done: 58565c4583b2SJeff Layton if (status == nfs_ok && nfp) 58575c4583b2SJeff Layton status = nfs4_check_file(rqstp, fhp, s, nfp, flags); 58581da177e4SLinus Torvalds out: 5859624322f1SOlga Kornievskaia if (s) { 5860624322f1SOlga Kornievskaia if (!status && cstid) 5861624322f1SOlga Kornievskaia *cstid = s; 5862624322f1SOlga Kornievskaia else 5863fd911011STrond Myklebust nfs4_put_stid(s); 5864624322f1SOlga Kornievskaia } 58651da177e4SLinus Torvalds return status; 58661da177e4SLinus Torvalds } 58671da177e4SLinus Torvalds 5868e1ca12dfSBryan Schumaker /* 586917456804SBryan Schumaker * Test if the stateid is valid 587017456804SBryan Schumaker */ 587117456804SBryan Schumaker __be32 587217456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5873eb69853dSChristoph Hellwig union nfsd4_op_u *u) 587417456804SBryan Schumaker { 5875eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 587603cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 587703cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 587803cfb420SBryan Schumaker 587903cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 58807df302f7SChuck Lever stateid->ts_id_status = 58817df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 588203cfb420SBryan Schumaker 588317456804SBryan Schumaker return nfs_ok; 588417456804SBryan Schumaker } 588517456804SBryan Schumaker 588642691398SChuck Lever static __be32 588742691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 588842691398SChuck Lever { 588942691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 589042691398SChuck Lever __be32 ret; 589142691398SChuck Lever 5892659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 5893659aefb6STrond Myklebust if (ret) 5894659aefb6STrond Myklebust goto out_put_stid; 589542691398SChuck Lever 589642691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 589742691398SChuck Lever if (ret) 589842691398SChuck Lever goto out; 589942691398SChuck Lever 590042691398SChuck Lever ret = nfserr_locks_held; 590142691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 590242691398SChuck Lever lockowner(stp->st_stateowner))) 590342691398SChuck Lever goto out; 590442691398SChuck Lever 590542691398SChuck Lever release_lock_stateid(stp); 590642691398SChuck Lever ret = nfs_ok; 590742691398SChuck Lever 590842691398SChuck Lever out: 590942691398SChuck Lever mutex_unlock(&stp->st_mutex); 5910659aefb6STrond Myklebust out_put_stid: 591142691398SChuck Lever nfs4_put_stid(s); 591242691398SChuck Lever return ret; 591342691398SChuck Lever } 591442691398SChuck Lever 5915e1ca12dfSBryan Schumaker __be32 5916e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5917eb69853dSChristoph Hellwig union nfsd4_op_u *u) 5918e1ca12dfSBryan Schumaker { 5919eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 5920e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 59212da1cec7SJ. Bruce Fields struct nfs4_stid *s; 59223bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 592338c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 59242da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 5925e1ca12dfSBryan Schumaker 59261af71cc8SJeff Layton spin_lock(&cl->cl_lock); 59271af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 59282da1cec7SJ. Bruce Fields if (!s) 59291af71cc8SJeff Layton goto out_unlock; 593003da3169STrond Myklebust spin_lock(&s->sc_lock); 59312da1cec7SJ. Bruce Fields switch (s->sc_type) { 59322da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 5933e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 59341af71cc8SJeff Layton break; 59352da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 59361af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 59371af71cc8SJeff Layton if (ret) 59381af71cc8SJeff Layton break; 59391af71cc8SJeff Layton ret = nfserr_locks_held; 59401af71cc8SJeff Layton break; 59412da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 594203da3169STrond Myklebust spin_unlock(&s->sc_lock); 5943a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 59441af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 594542691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 59461af71cc8SJeff Layton goto out; 59473bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 594803da3169STrond Myklebust spin_unlock(&s->sc_lock); 59493bd64a5bSJ. Bruce Fields dp = delegstateid(s); 59502d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 59512d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 59526011695dSTrond Myklebust nfs4_put_stid(s); 59533bd64a5bSJ. Bruce Fields ret = nfs_ok; 59541af71cc8SJeff Layton goto out; 59551af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 5956e1ca12dfSBryan Schumaker } 595703da3169STrond Myklebust spin_unlock(&s->sc_lock); 59581af71cc8SJeff Layton out_unlock: 59591af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 5960e1ca12dfSBryan Schumaker out: 5961e1ca12dfSBryan Schumaker return ret; 5962e1ca12dfSBryan Schumaker } 5963e1ca12dfSBryan Schumaker 59644c4cd222SNeilBrown static inline int 59654c4cd222SNeilBrown setlkflg (int type) 59664c4cd222SNeilBrown { 59674c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 59684c4cd222SNeilBrown RD_STATE : WR_STATE; 59694c4cd222SNeilBrown } 59701da177e4SLinus Torvalds 5971dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 5972c0a5d93eSJ. Bruce Fields { 5973c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 5974c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 5975c0a5d93eSJ. Bruce Fields __be32 status; 5976c0a5d93eSJ. Bruce Fields 5977c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 5978c0a5d93eSJ. Bruce Fields if (status) 5979c0a5d93eSJ. Bruce Fields return status; 59809271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 59819271d7e5STrond Myklebust if (status != nfs_ok) 59829271d7e5STrond Myklebust return status; 5983f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 598435a92fe8SJeff Layton if (status == nfs_ok) 598535a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 598635a92fe8SJeff Layton if (status != nfs_ok) 5987feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 5988f7a4d872SJ. Bruce Fields return status; 5989c0a5d93eSJ. Bruce Fields } 5990c0a5d93eSJ. Bruce Fields 59911da177e4SLinus Torvalds /* 59921da177e4SLinus Torvalds * Checks for sequence id mutating operations. 59931da177e4SLinus Torvalds */ 5994b37ad28bSAl Viro static __be32 5995dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 59962288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 59973320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 59983320fef1SStanislav Kinsbursky struct nfsd_net *nn) 59991da177e4SLinus Torvalds { 60000836f587SJ. Bruce Fields __be32 status; 600138c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6002e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 60031da177e4SLinus Torvalds 6004dd5e3fbcSChuck Lever trace_nfsd_preprocess(seqid, stateid); 60051da177e4SLinus Torvalds 60061da177e4SLinus Torvalds *stpp = NULL; 60072dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 6008c0a5d93eSJ. Bruce Fields if (status) 6009c0a5d93eSJ. Bruce Fields return status; 6010e17f99b7STrond Myklebust stp = openlockstateid(s); 601158fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 60121da177e4SLinus Torvalds 6013e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 6014fd911011STrond Myklebust if (!status) 6015e17f99b7STrond Myklebust *stpp = stp; 6016fd911011STrond Myklebust else 6017fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 6018e17f99b7STrond Myklebust return status; 60191da177e4SLinus Torvalds } 60201da177e4SLinus Torvalds 60213320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 60223320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 6023c0a5d93eSJ. Bruce Fields { 6024c0a5d93eSJ. Bruce Fields __be32 status; 6025c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 60264cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 60271da177e4SLinus Torvalds 6028c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 60294cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 60300836f587SJ. Bruce Fields if (status) 60310836f587SJ. Bruce Fields return status; 60324cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 60334cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 6034feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 60354cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 6036c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 60374cbfc9f7STrond Myklebust } 60384cbfc9f7STrond Myklebust *stpp = stp; 60393a4f98bbSNeilBrown return nfs_ok; 60401da177e4SLinus Torvalds } 60411da177e4SLinus Torvalds 6042b37ad28bSAl Viro __be32 6043ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6044eb69853dSChristoph Hellwig union nfsd4_op_u *u) 60451da177e4SLinus Torvalds { 6046eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 6047b37ad28bSAl Viro __be32 status; 6048fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 6049dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 60503320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 60511da177e4SLinus Torvalds 6052a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 6053a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 60541da177e4SLinus Torvalds 6055ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 6056a8cddc5dSJ. Bruce Fields if (status) 6057a8cddc5dSJ. Bruce Fields return status; 60581da177e4SLinus Torvalds 60599072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 6060ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 60613320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 60629072d5c6SJ. Bruce Fields if (status) 60631da177e4SLinus Torvalds goto out; 6064fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 606568b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 606635a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 6067feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 60682585fc79STrond Myklebust goto put_stateid; 606935a92fe8SJeff Layton } 6070dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 60719767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 6072feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6073dd5e3fbcSChuck Lever trace_nfsd_open_confirm(oc->oc_seqid, &stp->st_stid.sc_stateid); 60742a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 607568b66e82SJ. Bruce Fields status = nfs_ok; 60762585fc79STrond Myklebust put_stateid: 60772585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 60781da177e4SLinus Torvalds out: 60799411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 60801da177e4SLinus Torvalds return status; 60811da177e4SLinus Torvalds } 60821da177e4SLinus Torvalds 60836409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 60841da177e4SLinus Torvalds { 608582c5ff1bSJeff Layton if (!test_access(access, stp)) 60866409a5a6SJ. Bruce Fields return; 608711b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 608882c5ff1bSJeff Layton clear_access(access, stp); 6089f197c271SJ. Bruce Fields } 60906409a5a6SJ. Bruce Fields 60916409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 60926409a5a6SJ. Bruce Fields { 60936409a5a6SJ. Bruce Fields switch (to_access) { 60946409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 60956409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 60966409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 60976409a5a6SJ. Bruce Fields break; 60986409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 60996409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 61006409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 61016409a5a6SJ. Bruce Fields break; 61026409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 61036409a5a6SJ. Bruce Fields break; 61046409a5a6SJ. Bruce Fields default: 6105063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 61061da177e4SLinus Torvalds } 61071da177e4SLinus Torvalds } 61081da177e4SLinus Torvalds 6109b37ad28bSAl Viro __be32 6110ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 6111eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 61121da177e4SLinus Torvalds { 6113eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 6114b37ad28bSAl Viro __be32 status; 6115dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 61163320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 61171da177e4SLinus Torvalds 6118a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 6119a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 61201da177e4SLinus Torvalds 6121c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 61222c8bd7e0SBenny Halevy if (od->od_deleg_want) 61232c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 61242c8bd7e0SBenny Halevy od->od_deleg_want); 61251da177e4SLinus Torvalds 6126c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 61273320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 61289072d5c6SJ. Bruce Fields if (status) 61291da177e4SLinus Torvalds goto out; 61301da177e4SLinus Torvalds status = nfserr_inval; 613182c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 6132c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 61331da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 61340667b1e9STrond Myklebust goto put_stateid; 61351da177e4SLinus Torvalds } 6136ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 6137c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 61381da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 61390667b1e9STrond Myklebust goto put_stateid; 61401da177e4SLinus Torvalds } 61416409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 6142ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 61439767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 61441da177e4SLinus Torvalds status = nfs_ok; 61450667b1e9STrond Myklebust put_stateid: 6146feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 61470667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 61481da177e4SLinus Torvalds out: 61499411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 61501da177e4SLinus Torvalds return status; 61511da177e4SLinus Torvalds } 61521da177e4SLinus Torvalds 6153f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 6154f7a4d872SJ. Bruce Fields { 6155acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 6156e8568739SJeff Layton bool unhashed; 6157d83017f9SJeff Layton LIST_HEAD(reaplist); 6158acf9295bSTrond Myklebust 61592c41beb0SJeff Layton spin_lock(&clp->cl_lock); 6160e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 6161acf9295bSTrond Myklebust 6162d83017f9SJeff Layton if (clp->cl_minorversion) { 6163e8568739SJeff Layton if (unhashed) 6164d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 6165d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6166d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6167d83017f9SJeff Layton } else { 6168d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6169d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6170e8568739SJeff Layton if (unhashed) 6171d3134b10SJeff Layton move_to_close_lru(s, clp->net); 617238c387b5SJ. Bruce Fields } 6173d83017f9SJeff Layton } 617438c387b5SJ. Bruce Fields 61751da177e4SLinus Torvalds /* 61761da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 61771da177e4SLinus Torvalds */ 6178b37ad28bSAl Viro __be32 6179ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6180eb69853dSChristoph Hellwig union nfsd4_op_u *u) 61811da177e4SLinus Torvalds { 6182eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 6183b37ad28bSAl Viro __be32 status; 6184dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 61853320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 61863320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 61871da177e4SLinus Torvalds 6188a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 6189a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 61901da177e4SLinus Torvalds 6191f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 6192f7a4d872SJ. Bruce Fields &close->cl_stateid, 6193f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 61943320fef1SStanislav Kinsbursky &stp, nn); 61959411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 61969072d5c6SJ. Bruce Fields if (status) 61971da177e4SLinus Torvalds goto out; 619815ca08d3STrond Myklebust 619915ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 6200bd2decacSJeff Layton 6201bd2decacSJeff Layton /* 6202bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 6203bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 6204bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 6205bd2decacSJeff Layton * that racing ops see that there was a state change. 6206bd2decacSJeff Layton */ 62079767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 62081da177e4SLinus Torvalds 6209f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 621015ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 62118a0b589dSTrond Myklebust 6212bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 6213bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 6214bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 6215bd2decacSJeff Layton * universally. 6216bd2decacSJeff Layton * 6217bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 6218bd2decacSJeff Layton */ 6219bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 6220fb500a7cSTrond Myklebust 62218a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 62228a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 62231da177e4SLinus Torvalds out: 62241da177e4SLinus Torvalds return status; 62251da177e4SLinus Torvalds } 62261da177e4SLinus Torvalds 6227b37ad28bSAl Viro __be32 6228ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6229eb69853dSChristoph Hellwig union nfsd4_op_u *u) 62301da177e4SLinus Torvalds { 6231eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 6232203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 6233203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 623438c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6235b37ad28bSAl Viro __be32 status; 62363320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 62371da177e4SLinus Torvalds 6238ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 6239203a8c8eSJ. Bruce Fields return status; 62401da177e4SLinus Torvalds 62412dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 624238c2f4b1SJ. Bruce Fields if (status) 6243203a8c8eSJ. Bruce Fields goto out; 624438c2f4b1SJ. Bruce Fields dp = delegstateid(s); 624503da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 6246203a8c8eSJ. Bruce Fields if (status) 6247fd911011STrond Myklebust goto put_stateid; 6248203a8c8eSJ. Bruce Fields 62493bd64a5bSJ. Bruce Fields destroy_delegation(dp); 6250fd911011STrond Myklebust put_stateid: 6251fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 62521da177e4SLinus Torvalds out: 62531da177e4SLinus Torvalds return status; 62541da177e4SLinus Torvalds } 62551da177e4SLinus Torvalds 625687df4de8SBenny Halevy static inline u64 625787df4de8SBenny Halevy end_offset(u64 start, u64 len) 625887df4de8SBenny Halevy { 625987df4de8SBenny Halevy u64 end; 626087df4de8SBenny Halevy 626187df4de8SBenny Halevy end = start + len; 626287df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 626387df4de8SBenny Halevy } 626487df4de8SBenny Halevy 626587df4de8SBenny Halevy /* last octet in a range */ 626687df4de8SBenny Halevy static inline u64 626787df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 626887df4de8SBenny Halevy { 626987df4de8SBenny Halevy u64 end; 627087df4de8SBenny Halevy 6271063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 627287df4de8SBenny Halevy end = start + len; 627387df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 627487df4de8SBenny Halevy } 627587df4de8SBenny Halevy 62761da177e4SLinus Torvalds /* 62771da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 62781da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 62791da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 62801da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 62811da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 62821da177e4SLinus Torvalds * the VFS, but this is a very deep change! 62831da177e4SLinus Torvalds */ 62841da177e4SLinus Torvalds static inline void 62851da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 62861da177e4SLinus Torvalds { 62871da177e4SLinus Torvalds if (lock->fl_start < 0) 62881da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 62891da177e4SLinus Torvalds if (lock->fl_end < 0) 62901da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 62911da177e4SLinus Torvalds } 62921da177e4SLinus Torvalds 6293cae80b30SJeff Layton static fl_owner_t 6294cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner) 6295aef9583bSKinglong Mee { 6296cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6297cae80b30SJeff Layton 6298cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 6299cae80b30SJeff Layton return owner; 6300aef9583bSKinglong Mee } 6301aef9583bSKinglong Mee 6302cae80b30SJeff Layton static void 6303cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner) 6304aef9583bSKinglong Mee { 6305cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6306aef9583bSKinglong Mee 6307cae80b30SJeff Layton if (lo) 6308aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 6309aef9583bSKinglong Mee } 6310aef9583bSKinglong Mee 631176d348faSJeff Layton static void 631276d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 631376d348faSJeff Layton { 631476d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 631576d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 631676d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 631776d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 631876d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 631976d348faSJeff Layton bool queue = false; 632076d348faSJeff Layton 63217919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 63220cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 632376d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 632476d348faSJeff Layton list_del_init(&nbl->nbl_list); 63257919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 632676d348faSJeff Layton queue = true; 632776d348faSJeff Layton } 63280cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 632976d348faSJeff Layton 633076d348faSJeff Layton if (queue) 633176d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 633276d348faSJeff Layton } 633376d348faSJeff Layton 63347b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 633576d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 6336aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 6337aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 6338d5b9026aSNeilBrown }; 63391da177e4SLinus Torvalds 63401da177e4SLinus Torvalds static inline void 63411da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 63421da177e4SLinus Torvalds { 6343fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 63441da177e4SLinus Torvalds 6345d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 6346fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 63476f4859b8SJ. Bruce Fields xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner, 63486f4859b8SJ. Bruce Fields GFP_KERNEL); 63497c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 63507c13f344SJ. Bruce Fields /* We just don't care that much */ 63517c13f344SJ. Bruce Fields goto nevermind; 6352fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 6353d5b9026aSNeilBrown } else { 63547c13f344SJ. Bruce Fields nevermind: 63557c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 63567c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 6357d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 6358d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 63591da177e4SLinus Torvalds } 63601da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 636187df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 636287df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 63631da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 63641da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 63651da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 63661da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 63671da177e4SLinus Torvalds } 63681da177e4SLinus Torvalds 6369fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6370c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 63711da177e4SLinus Torvalds { 6372d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 6373b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 63741da177e4SLinus Torvalds 63750a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 63760a880a28STrond Myklebust 6377d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 6378d4f0489fSTrond Myklebust so_strhash) { 6379b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 6380b3c32bcdSTrond Myklebust continue; 6381b5971afaSKinglong Mee if (same_owner_str(so, owner)) 6382b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 63831da177e4SLinus Torvalds } 63841da177e4SLinus Torvalds return NULL; 63851da177e4SLinus Torvalds } 63861da177e4SLinus Torvalds 6387c58c6610STrond Myklebust static struct nfs4_lockowner * 6388c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 6389c58c6610STrond Myklebust { 6390c58c6610STrond Myklebust struct nfs4_lockowner *lo; 6391c58c6610STrond Myklebust 6392d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6393c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 6394d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6395c58c6610STrond Myklebust return lo; 6396c58c6610STrond Myklebust } 6397c58c6610STrond Myklebust 63988f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 63998f4b54c5SJeff Layton { 6400c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 64018f4b54c5SJeff Layton } 64028f4b54c5SJeff Layton 64036b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 64046b180f0bSJeff Layton { 64056b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 64066b180f0bSJeff Layton 64076b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 64086b180f0bSJeff Layton } 64096b180f0bSJeff Layton 64106b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 64118f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 64126b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 64136b180f0bSJeff Layton }; 64146b180f0bSJeff Layton 64151da177e4SLinus Torvalds /* 64161da177e4SLinus Torvalds * Alloc a lock owner structure. 64171da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 641825985edcSLucas De Marchi * occurred. 64191da177e4SLinus Torvalds * 642016bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 64211da177e4SLinus Torvalds */ 6422fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6423c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 6424c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 6425c58c6610STrond Myklebust struct nfsd4_lock *lock) 6426c58c6610STrond Myklebust { 6427c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 64281da177e4SLinus Torvalds 6429fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 6430fe0750e5SJ. Bruce Fields if (!lo) 64311da177e4SLinus Torvalds return NULL; 643276d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 6433fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 6434fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 64355db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 64366b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 6437d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6438c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 6439c58c6610STrond Myklebust if (ret == NULL) { 6440c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 6441d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 6442c58c6610STrond Myklebust ret = lo; 6443c58c6610STrond Myklebust } else 6444d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 6445d50ffdedSKinglong Mee 6446d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6447340f0ba1SJ. Bruce Fields return ret; 64481da177e4SLinus Torvalds } 64491da177e4SLinus Torvalds 6450fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 6451a451b123STrond Myklebust find_lock_stateid(const struct nfs4_lockowner *lo, 6452a451b123STrond Myklebust const struct nfs4_ol_stateid *ost) 6453fd1fd685STrond Myklebust { 6454fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 6455fd1fd685STrond Myklebust 6456a451b123STrond Myklebust lockdep_assert_held(&ost->st_stid.sc_client->cl_lock); 6457fd1fd685STrond Myklebust 6458a451b123STrond Myklebust /* If ost is not hashed, ost->st_locks will not be valid */ 6459a451b123STrond Myklebust if (!nfs4_ol_stateid_unhashed(ost)) 6460a451b123STrond Myklebust list_for_each_entry(lst, &ost->st_locks, st_locks) { 6461a451b123STrond Myklebust if (lst->st_stateowner == &lo->lo_owner) { 6462fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 6463fd1fd685STrond Myklebust return lst; 6464fd1fd685STrond Myklebust } 6465fd1fd685STrond Myklebust } 6466fd1fd685STrond Myklebust return NULL; 6467fd1fd685STrond Myklebust } 6468fd1fd685STrond Myklebust 6469beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 6470356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 6471356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 6472f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 64731da177e4SLinus Torvalds { 6474d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 6475beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 64761da177e4SLinus Torvalds 6477beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 64784f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 6479beeca19cSTrond Myklebust retry: 6480beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 6481a451b123STrond Myklebust if (nfs4_ol_stateid_unhashed(open_stp)) 6482a451b123STrond Myklebust goto out_close; 6483a451b123STrond Myklebust retstp = find_lock_stateid(lo, open_stp); 6484beeca19cSTrond Myklebust if (retstp) 6485a451b123STrond Myklebust goto out_found; 6486a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 64873abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 6488b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 648913cd2184SNeilBrown get_nfs4_file(fp); 649011b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 64910997b173SJ. Bruce Fields stp->st_access_bmap = 0; 64921da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 64934c4cd222SNeilBrown stp->st_openstp = open_stp; 6494a451b123STrond Myklebust spin_lock(&fp->fi_lock); 64953c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 64961c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 64971d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 64981d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 6499beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 6500a451b123STrond Myklebust return stp; 6501a451b123STrond Myklebust out_found: 6502a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 6503beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 6504beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 6505beeca19cSTrond Myklebust goto retry; 6506beeca19cSTrond Myklebust } 6507beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 6508beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 6509a451b123STrond Myklebust return retstp; 6510a451b123STrond Myklebust out_close: 6511a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 6512a451b123STrond Myklebust mutex_unlock(&stp->st_mutex); 6513a451b123STrond Myklebust return NULL; 65141da177e4SLinus Torvalds } 65151da177e4SLinus Torvalds 6516c53530daSJeff Layton static struct nfs4_ol_stateid * 6517356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 6518356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 6519356a95ecSJeff Layton bool *new) 6520356a95ecSJeff Layton { 6521356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 6522356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 6523356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 6524356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 6525356a95ecSJeff Layton 6526beeca19cSTrond Myklebust *new = false; 6527356a95ecSJeff Layton spin_lock(&clp->cl_lock); 6528a451b123STrond Myklebust lst = find_lock_stateid(lo, ost); 6529356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 6530beeca19cSTrond Myklebust if (lst != NULL) { 6531beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 6532beeca19cSTrond Myklebust goto out; 6533beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 6534beeca19cSTrond Myklebust } 6535d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 6536356a95ecSJeff Layton if (ns == NULL) 6537356a95ecSJeff Layton return NULL; 6538356a95ecSJeff Layton 6539beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 6540beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 6541356a95ecSJeff Layton *new = true; 6542beeca19cSTrond Myklebust else 6543356a95ecSJeff Layton nfs4_put_stid(ns); 6544beeca19cSTrond Myklebust out: 6545356a95ecSJeff Layton return lst; 6546356a95ecSJeff Layton } 6547c53530daSJeff Layton 6548fd39ca9aSNeilBrown static int 65491da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 65501da177e4SLinus Torvalds { 655187df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 6552e7969315SKinglong Mee (length > ~offset))); 65531da177e4SLinus Torvalds } 65541da177e4SLinus Torvalds 6555dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 65560997b173SJ. Bruce Fields { 655711b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 65580997b173SJ. Bruce Fields 65597214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 65607214e860SJeff Layton 656182c5ff1bSJeff Layton if (test_access(access, lock_stp)) 65620997b173SJ. Bruce Fields return; 656312659651SJeff Layton __nfs4_file_get_access(fp, access); 656482c5ff1bSJeff Layton set_access(access, lock_stp); 65650997b173SJ. Bruce Fields } 65660997b173SJ. Bruce Fields 6567356a95ecSJeff Layton static __be32 6568356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 6569356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 6570356a95ecSJeff Layton struct nfsd4_lock *lock, 6571dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 657264a284d0SJ. Bruce Fields { 65735db1c03fSJeff Layton __be32 status; 657411b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 657564a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 657664a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 65772b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 657864a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 6579dd257933SJeff Layton struct nfs4_ol_stateid *lst; 658064a284d0SJ. Bruce Fields unsigned int strhashval; 658164a284d0SJ. Bruce Fields 6582c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 6583c53530daSJeff Layton if (!lo) { 658476f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 658564a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 658664a284d0SJ. Bruce Fields if (lo == NULL) 658764a284d0SJ. Bruce Fields return nfserr_jukebox; 6588c53530daSJeff Layton } else { 6589c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 65905db1c03fSJeff Layton status = nfserr_bad_seqid; 6591c53530daSJeff Layton if (!cstate->minorversion && 6592c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 65935db1c03fSJeff Layton goto out; 6594c53530daSJeff Layton } 6595c53530daSJeff Layton 6596dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 6597dd257933SJeff Layton if (lst == NULL) { 65985db1c03fSJeff Layton status = nfserr_jukebox; 65995db1c03fSJeff Layton goto out; 660064a284d0SJ. Bruce Fields } 6601dd257933SJeff Layton 66025db1c03fSJeff Layton status = nfs_ok; 6603dd257933SJeff Layton *plst = lst; 66045db1c03fSJeff Layton out: 66055db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 66065db1c03fSJeff Layton return status; 660764a284d0SJ. Bruce Fields } 660864a284d0SJ. Bruce Fields 66091da177e4SLinus Torvalds /* 66101da177e4SLinus Torvalds * LOCK operation 66111da177e4SLinus Torvalds */ 6612b37ad28bSAl Viro __be32 6613ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6614eb69853dSChristoph Hellwig union nfsd4_op_u *u) 66151da177e4SLinus Torvalds { 6616eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 6617fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 6618fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 66193d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 66200667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 66217214e860SJeff Layton struct nfs4_file *fp; 6622eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 662376d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 662421179d81SJeff Layton struct file_lock *file_lock = NULL; 662521179d81SJeff Layton struct file_lock *conflock = NULL; 6626b37ad28bSAl Viro __be32 status = 0; 6627b34f27aaSJ. Bruce Fields int lkflg; 6628b8dd7b9aSAl Viro int err; 66295db1c03fSJeff Layton bool new = false; 663076d348faSJeff Layton unsigned char fl_type; 663176d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 66323320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 66333320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 66341da177e4SLinus Torvalds 66351da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 66361da177e4SLinus Torvalds (long long) lock->lk_offset, 66371da177e4SLinus Torvalds (long long) lock->lk_length); 66381da177e4SLinus Torvalds 66391da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 66401da177e4SLinus Torvalds return nfserr_inval; 66411da177e4SLinus Torvalds 6642ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 66438837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 6644a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 6645a6f6ef2fSAndy Adamson return status; 6646a6f6ef2fSAndy Adamson } 6647a6f6ef2fSAndy Adamson 66481da177e4SLinus Torvalds if (lock->lk_is_new) { 6649684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 6650684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 665176f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 6652684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 6653684e5638SJ. Bruce Fields sizeof(clientid_t)); 6654684e5638SJ. Bruce Fields 66551da177e4SLinus Torvalds status = nfserr_stale_clientid; 66562c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 66571da177e4SLinus Torvalds goto out; 66581da177e4SLinus Torvalds 66591da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 6660c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 66611da177e4SLinus Torvalds lock->lk_new_open_seqid, 66621da177e4SLinus Torvalds &lock->lk_new_open_stateid, 66633320fef1SStanislav Kinsbursky &open_stp, nn); 666437515177SNeilBrown if (status) 66651da177e4SLinus Torvalds goto out; 6666feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 6667fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 6668b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 6669684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 667076f6c9e1SKinglong Mee &lock->lk_new_clientid)) 6671b34f27aaSJ. Bruce Fields goto out; 667264a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 66735db1c03fSJeff Layton &lock_stp, &new); 66743d0fabd5STrond Myklebust } else { 6675dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 66761da177e4SLinus Torvalds lock->lk_old_lock_seqid, 66771da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 66783320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 66793d0fabd5STrond Myklebust } 66801da177e4SLinus Torvalds if (status) 66811da177e4SLinus Torvalds goto out; 6682fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 66831da177e4SLinus Torvalds 6684b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 6685b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 6686b34f27aaSJ. Bruce Fields if (status) 6687b34f27aaSJ. Bruce Fields goto out; 6688b34f27aaSJ. Bruce Fields 66890dd395dcSNeilBrown status = nfserr_grace; 66903320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 66910dd395dcSNeilBrown goto out; 66920dd395dcSNeilBrown status = nfserr_no_grace; 66933320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 66940dd395dcSNeilBrown goto out; 66950dd395dcSNeilBrown 669611b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 66971da177e4SLinus Torvalds switch (lock->lk_type) { 66981da177e4SLinus Torvalds case NFS4_READW_LT: 669976d348faSJeff Layton if (nfsd4_has_session(cstate)) 670076d348faSJeff Layton fl_flags |= FL_SLEEP; 670176d348faSJeff Layton /* Fallthrough */ 670276d348faSJeff Layton case NFS4_READ_LT: 67037214e860SJeff Layton spin_lock(&fp->fi_lock); 6704eb82dd39SJeff Layton nf = find_readable_file_locked(fp); 6705eb82dd39SJeff Layton if (nf) 67060997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 67077214e860SJeff Layton spin_unlock(&fp->fi_lock); 670876d348faSJeff Layton fl_type = F_RDLCK; 67091da177e4SLinus Torvalds break; 67101da177e4SLinus Torvalds case NFS4_WRITEW_LT: 671176d348faSJeff Layton if (nfsd4_has_session(cstate)) 671276d348faSJeff Layton fl_flags |= FL_SLEEP; 671376d348faSJeff Layton /* Fallthrough */ 671476d348faSJeff Layton case NFS4_WRITE_LT: 67157214e860SJeff Layton spin_lock(&fp->fi_lock); 6716eb82dd39SJeff Layton nf = find_writeable_file_locked(fp); 6717eb82dd39SJeff Layton if (nf) 67180997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 67197214e860SJeff Layton spin_unlock(&fp->fi_lock); 672076d348faSJeff Layton fl_type = F_WRLCK; 67211da177e4SLinus Torvalds break; 67221da177e4SLinus Torvalds default: 67231da177e4SLinus Torvalds status = nfserr_inval; 67241da177e4SLinus Torvalds goto out; 67251da177e4SLinus Torvalds } 672676d348faSJeff Layton 6727eb82dd39SJeff Layton if (!nf) { 6728f9d7562fSJ. Bruce Fields status = nfserr_openmode; 6729f9d7562fSJ. Bruce Fields goto out; 6730f9d7562fSJ. Bruce Fields } 6731aef9583bSKinglong Mee 673276d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 673376d348faSJeff Layton if (!nbl) { 673476d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 673576d348faSJeff Layton status = nfserr_jukebox; 673676d348faSJeff Layton goto out; 673776d348faSJeff Layton } 673876d348faSJeff Layton 673976d348faSJeff Layton file_lock = &nbl->nbl_lock; 674076d348faSJeff Layton file_lock->fl_type = fl_type; 6741aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 674221179d81SJeff Layton file_lock->fl_pid = current->tgid; 6743eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 674476d348faSJeff Layton file_lock->fl_flags = fl_flags; 674521179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 674621179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 674721179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 674821179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 67491da177e4SLinus Torvalds 675021179d81SJeff Layton conflock = locks_alloc_lock(); 675121179d81SJeff Layton if (!conflock) { 675221179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 675321179d81SJeff Layton status = nfserr_jukebox; 675421179d81SJeff Layton goto out; 675521179d81SJeff Layton } 67561da177e4SLinus Torvalds 675776d348faSJeff Layton if (fl_flags & FL_SLEEP) { 675820b7d86fSArnd Bergmann nbl->nbl_time = ktime_get_boottime_seconds(); 67590cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 676076d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 67617919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 67620cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 676376d348faSJeff Layton } 676476d348faSJeff Layton 6765eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, conflock); 676676d348faSJeff Layton switch (err) { 67671da177e4SLinus Torvalds case 0: /* success! */ 67689767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 6769b8dd7b9aSAl Viro status = 0; 677003f318caSJ. Bruce Fields if (lock->lk_reclaim) 677103f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 6772eb76b3fdSAndy Adamson break; 677376d348faSJeff Layton case FILE_LOCK_DEFERRED: 677476d348faSJeff Layton nbl = NULL; 677576d348faSJeff Layton /* Fallthrough */ 677676d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 6777eb76b3fdSAndy Adamson status = nfserr_denied; 6778eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 677921179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 6780eb76b3fdSAndy Adamson break; 678176d348faSJeff Layton case -EDEADLK: 67821da177e4SLinus Torvalds status = nfserr_deadlock; 6783eb76b3fdSAndy Adamson break; 67841da177e4SLinus Torvalds default: 6785fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 67863e772463SJ. Bruce Fields status = nfserrno(err); 6787eb76b3fdSAndy Adamson break; 67881da177e4SLinus Torvalds } 67891da177e4SLinus Torvalds out: 679076d348faSJeff Layton if (nbl) { 679176d348faSJeff Layton /* dequeue it if we queued it before */ 679276d348faSJeff Layton if (fl_flags & FL_SLEEP) { 67930cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 679476d348faSJeff Layton list_del_init(&nbl->nbl_list); 67957919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 67960cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 679776d348faSJeff Layton } 679876d348faSJeff Layton free_blocked_lock(nbl); 679976d348faSJeff Layton } 6800eb82dd39SJeff Layton if (nf) 6801eb82dd39SJeff Layton nfsd_file_put(nf); 68025db1c03fSJeff Layton if (lock_stp) { 68035db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 68045db1c03fSJeff Layton if (cstate->replay_owner && 68055db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 68065db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 68075db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 68085db1c03fSJeff Layton 68095db1c03fSJeff Layton /* 68105db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 68115db1c03fSJeff Layton * returning an error, then just go ahead and release it. 68125db1c03fSJeff Layton */ 681325020720SJ. Bruce Fields if (status && new) 68145db1c03fSJeff Layton release_lock_stateid(lock_stp); 6815beeca19cSTrond Myklebust 6816beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 68175db1c03fSJeff Layton 68183d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 68195db1c03fSJeff Layton } 68200667b1e9STrond Myklebust if (open_stp) 68210667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 68229411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 682321179d81SJeff Layton if (conflock) 682421179d81SJeff Layton locks_free_lock(conflock); 68251da177e4SLinus Torvalds return status; 68261da177e4SLinus Torvalds } 68271da177e4SLinus Torvalds 68281da177e4SLinus Torvalds /* 682955ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 683055ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 683155ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 683255ef1274SJ. Bruce Fields * inode operation.) 683355ef1274SJ. Bruce Fields */ 683404da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 683555ef1274SJ. Bruce Fields { 68366b556ca2SJeff Layton struct nfsd_file *nf; 68376b556ca2SJeff Layton __be32 err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); 683804da6e9dSAl Viro if (!err) { 68396b556ca2SJeff Layton err = nfserrno(vfs_test_lock(nf->nf_file, lock)); 68406b556ca2SJeff Layton nfsd_file_put(nf); 684104da6e9dSAl Viro } 684255ef1274SJ. Bruce Fields return err; 684355ef1274SJ. Bruce Fields } 684455ef1274SJ. Bruce Fields 684555ef1274SJ. Bruce Fields /* 68461da177e4SLinus Torvalds * LOCKT operation 68471da177e4SLinus Torvalds */ 6848b37ad28bSAl Viro __be32 6849ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6850eb69853dSChristoph Hellwig union nfsd4_op_u *u) 68511da177e4SLinus Torvalds { 6852eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 685321179d81SJeff Layton struct file_lock *file_lock = NULL; 68545db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 6855b37ad28bSAl Viro __be32 status; 68567f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 68571da177e4SLinus Torvalds 68585ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 68591da177e4SLinus Torvalds return nfserr_grace; 68601da177e4SLinus Torvalds 68611da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 68621da177e4SLinus Torvalds return nfserr_inval; 68631da177e4SLinus Torvalds 68649b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 6865b7342204SOlga Kornievskaia status = lookup_clientid(&lockt->lt_clientid, cstate, nn, 6866b7342204SOlga Kornievskaia false); 68679b2ef62bSJ. Bruce Fields if (status) 68681da177e4SLinus Torvalds goto out; 68699b2ef62bSJ. Bruce Fields } 68701da177e4SLinus Torvalds 687175c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 68721da177e4SLinus Torvalds goto out; 68731da177e4SLinus Torvalds 687421179d81SJeff Layton file_lock = locks_alloc_lock(); 687521179d81SJeff Layton if (!file_lock) { 687621179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 687721179d81SJeff Layton status = nfserr_jukebox; 687821179d81SJeff Layton goto out; 687921179d81SJeff Layton } 68806cd90662SKinglong Mee 68811da177e4SLinus Torvalds switch (lockt->lt_type) { 68821da177e4SLinus Torvalds case NFS4_READ_LT: 68831da177e4SLinus Torvalds case NFS4_READW_LT: 688421179d81SJeff Layton file_lock->fl_type = F_RDLCK; 68851da177e4SLinus Torvalds break; 68861da177e4SLinus Torvalds case NFS4_WRITE_LT: 68871da177e4SLinus Torvalds case NFS4_WRITEW_LT: 688821179d81SJeff Layton file_lock->fl_type = F_WRLCK; 68891da177e4SLinus Torvalds break; 68901da177e4SLinus Torvalds default: 68912fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 68921da177e4SLinus Torvalds status = nfserr_inval; 68931da177e4SLinus Torvalds goto out; 68941da177e4SLinus Torvalds } 68951da177e4SLinus Torvalds 6896c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 6897fe0750e5SJ. Bruce Fields if (lo) 689821179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 689921179d81SJeff Layton file_lock->fl_pid = current->tgid; 690021179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 69011da177e4SLinus Torvalds 690221179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 690321179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 69041da177e4SLinus Torvalds 690521179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 69061da177e4SLinus Torvalds 690721179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 690804da6e9dSAl Viro if (status) 6909fd85b817SMarc Eshel goto out; 691004da6e9dSAl Viro 691121179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 69121da177e4SLinus Torvalds status = nfserr_denied; 691321179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 69141da177e4SLinus Torvalds } 69151da177e4SLinus Torvalds out: 69165db1c03fSJeff Layton if (lo) 69175db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 691821179d81SJeff Layton if (file_lock) 691921179d81SJeff Layton locks_free_lock(file_lock); 69201da177e4SLinus Torvalds return status; 69211da177e4SLinus Torvalds } 69221da177e4SLinus Torvalds 6923b37ad28bSAl Viro __be32 6924ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6925eb69853dSChristoph Hellwig union nfsd4_op_u *u) 69261da177e4SLinus Torvalds { 6927eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 6928dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 6929eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 693021179d81SJeff Layton struct file_lock *file_lock = NULL; 6931b37ad28bSAl Viro __be32 status; 6932b8dd7b9aSAl Viro int err; 69333320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 69341da177e4SLinus Torvalds 69351da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 69361da177e4SLinus Torvalds (long long) locku->lu_offset, 69371da177e4SLinus Torvalds (long long) locku->lu_length); 69381da177e4SLinus Torvalds 69391da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 69401da177e4SLinus Torvalds return nfserr_inval; 69411da177e4SLinus Torvalds 69429072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 69433320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 69443320fef1SStanislav Kinsbursky &stp, nn); 69459072d5c6SJ. Bruce Fields if (status) 69461da177e4SLinus Torvalds goto out; 6947eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 6948eb82dd39SJeff Layton if (!nf) { 6949f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 6950858cc573STrond Myklebust goto put_stateid; 6951f9d7562fSJ. Bruce Fields } 695221179d81SJeff Layton file_lock = locks_alloc_lock(); 695321179d81SJeff Layton if (!file_lock) { 695421179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 695521179d81SJeff Layton status = nfserr_jukebox; 6956eb82dd39SJeff Layton goto put_file; 695721179d81SJeff Layton } 69586cd90662SKinglong Mee 695921179d81SJeff Layton file_lock->fl_type = F_UNLCK; 6960aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 696121179d81SJeff Layton file_lock->fl_pid = current->tgid; 6962eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 696321179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 696421179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 696521179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 69661da177e4SLinus Torvalds 696721179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 696821179d81SJeff Layton locku->lu_length); 696921179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 69701da177e4SLinus Torvalds 6971eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, NULL); 6972b8dd7b9aSAl Viro if (err) { 6973fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 69741da177e4SLinus Torvalds goto out_nfserr; 69751da177e4SLinus Torvalds } 69769767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 6977eb82dd39SJeff Layton put_file: 6978eb82dd39SJeff Layton nfsd_file_put(nf); 6979858cc573STrond Myklebust put_stateid: 6980feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6981858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 69821da177e4SLinus Torvalds out: 69839411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 698421179d81SJeff Layton if (file_lock) 698521179d81SJeff Layton locks_free_lock(file_lock); 69861da177e4SLinus Torvalds return status; 69871da177e4SLinus Torvalds 69881da177e4SLinus Torvalds out_nfserr: 6989b8dd7b9aSAl Viro status = nfserrno(err); 6990eb82dd39SJeff Layton goto put_file; 69911da177e4SLinus Torvalds } 69921da177e4SLinus Torvalds 69931da177e4SLinus Torvalds /* 69941da177e4SLinus Torvalds * returns 6995f9c00c3aSJeff Layton * true: locks held by lockowner 6996f9c00c3aSJeff Layton * false: no locks held by lockowner 69971da177e4SLinus Torvalds */ 6998f9c00c3aSJeff Layton static bool 6999f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 70001da177e4SLinus Torvalds { 7001bd61e0a9SJeff Layton struct file_lock *fl; 7002f9c00c3aSJeff Layton int status = false; 7003eb82dd39SJeff Layton struct nfsd_file *nf = find_any_file(fp); 7004f9c00c3aSJeff Layton struct inode *inode; 7005bd61e0a9SJeff Layton struct file_lock_context *flctx; 7006f9c00c3aSJeff Layton 7007eb82dd39SJeff Layton if (!nf) { 7008f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 7009f9c00c3aSJeff Layton WARN_ON_ONCE(1); 7010f9c00c3aSJeff Layton return status; 7011f9c00c3aSJeff Layton } 7012f9c00c3aSJeff Layton 7013eb82dd39SJeff Layton inode = locks_inode(nf->nf_file); 7014bd61e0a9SJeff Layton flctx = inode->i_flctx; 70151da177e4SLinus Torvalds 7016bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 70176109c850SJeff Layton spin_lock(&flctx->flc_lock); 7018bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 7019bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 7020f9c00c3aSJeff Layton status = true; 7021f9c00c3aSJeff Layton break; 70221da177e4SLinus Torvalds } 7023796dadfdSJ. Bruce Fields } 70246109c850SJeff Layton spin_unlock(&flctx->flc_lock); 7025bd61e0a9SJeff Layton } 7026eb82dd39SJeff Layton nfsd_file_put(nf); 70271da177e4SLinus Torvalds return status; 70281da177e4SLinus Torvalds } 70291da177e4SLinus Torvalds 7030b37ad28bSAl Viro __be32 7031b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 7032b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 7033eb69853dSChristoph Hellwig union nfsd4_op_u *u) 70341da177e4SLinus Torvalds { 7035eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 70361da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 7037882e9d25SJeff Layton struct nfs4_stateowner *sop; 7038882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 7039dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 70401da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 7041d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 7042b37ad28bSAl Viro __be32 status; 70437f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 7044c58c6610STrond Myklebust struct nfs4_client *clp; 704588584818SChuck Lever LIST_HEAD (reaplist); 70461da177e4SLinus Torvalds 70471da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 70481da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 70491da177e4SLinus Torvalds 7050b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 70519b2ef62bSJ. Bruce Fields if (status) 705251f5e783STrond Myklebust return status; 70539b2ef62bSJ. Bruce Fields 7054d4f0489fSTrond Myklebust clp = cstate->clp; 7055fd44907cSJeff Layton /* Find the matching lock stateowner */ 7056d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7057882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 7058d4f0489fSTrond Myklebust so_strhash) { 7059882e9d25SJeff Layton 7060882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 706116bfdaafSJ. Bruce Fields continue; 7062882e9d25SJeff Layton 7063882e9d25SJeff Layton /* see if there are still any locks associated with it */ 7064882e9d25SJeff Layton lo = lockowner(sop); 7065882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 7066882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 7067882e9d25SJeff Layton status = nfserr_locks_held; 7068882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 706951f5e783STrond Myklebust return status; 7070882e9d25SJeff Layton } 7071882e9d25SJeff Layton } 7072882e9d25SJeff Layton 7073b5971afaSKinglong Mee nfs4_get_stateowner(sop); 7074fd44907cSJeff Layton break; 7075fd44907cSJeff Layton } 707688584818SChuck Lever if (!lo) { 7077d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 707888584818SChuck Lever return status; 707988584818SChuck Lever } 708088584818SChuck Lever 708188584818SChuck Lever unhash_lockowner_locked(lo); 708288584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 708388584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 708488584818SChuck Lever struct nfs4_ol_stateid, 708588584818SChuck Lever st_perstateowner); 708688584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 708788584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 708888584818SChuck Lever } 708988584818SChuck Lever spin_unlock(&clp->cl_lock); 709088584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 709168ef3bc3SJeff Layton remove_blocked_locks(lo); 709288584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 709388584818SChuck Lever 70941da177e4SLinus Torvalds return status; 70951da177e4SLinus Torvalds } 70961da177e4SLinus Torvalds 70971da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 7098a55370a3SNeilBrown alloc_reclaim(void) 70991da177e4SLinus Torvalds { 7100a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 71011da177e4SLinus Torvalds } 71021da177e4SLinus Torvalds 71030ce0c2b5SJeff Layton bool 71046b189105SScott Mayhew nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) 7105c7b9a459SNeilBrown { 71060ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 7107c7b9a459SNeilBrown 710852e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 71090ce0c2b5SJeff Layton return (crp && crp->cr_clp); 7110c7b9a459SNeilBrown } 7111c7b9a459SNeilBrown 71121da177e4SLinus Torvalds /* 71131da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 71146b189105SScott Mayhew * 71156b189105SScott Mayhew * The caller is responsible for freeing name.data if NULL is returned (it 71166b189105SScott Mayhew * will be freed in nfs4_remove_reclaim_record in the normal case). 71171da177e4SLinus Torvalds */ 7118772a9bbbSJeff Layton struct nfs4_client_reclaim * 71196ee95d1cSScott Mayhew nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, 71206ee95d1cSScott Mayhew struct nfsd_net *nn) 71211da177e4SLinus Torvalds { 71221da177e4SLinus Torvalds unsigned int strhashval; 7123772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 71241da177e4SLinus Torvalds 7125dd5e3fbcSChuck Lever trace_nfsd_clid_reclaim(nn, name.len, name.data); 7126a55370a3SNeilBrown crp = alloc_reclaim(); 7127772a9bbbSJeff Layton if (crp) { 7128a55370a3SNeilBrown strhashval = clientstr_hashval(name); 71291da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 713052e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 71316b189105SScott Mayhew crp->cr_name.data = name.data; 71326b189105SScott Mayhew crp->cr_name.len = name.len; 71336ee95d1cSScott Mayhew crp->cr_princhash.data = princhash.data; 71346ee95d1cSScott Mayhew crp->cr_princhash.len = princhash.len; 71350ce0c2b5SJeff Layton crp->cr_clp = NULL; 713652e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 7137772a9bbbSJeff Layton } 7138772a9bbbSJeff Layton return crp; 71391da177e4SLinus Torvalds } 71401da177e4SLinus Torvalds 71412a4317c5SJeff Layton void 714252e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 7143ce30e539SJeff Layton { 7144ce30e539SJeff Layton list_del(&crp->cr_strhash); 71456b189105SScott Mayhew kfree(crp->cr_name.data); 71466ee95d1cSScott Mayhew kfree(crp->cr_princhash.data); 7147ce30e539SJeff Layton kfree(crp); 714852e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 7149ce30e539SJeff Layton } 7150ce30e539SJeff Layton 7151ce30e539SJeff Layton void 715252e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 71531da177e4SLinus Torvalds { 71541da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 71551da177e4SLinus Torvalds int i; 71561da177e4SLinus Torvalds 71571da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 715852e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 715952e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 71601da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 716152e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 71621da177e4SLinus Torvalds } 71631da177e4SLinus Torvalds } 7164063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 71651da177e4SLinus Torvalds } 71661da177e4SLinus Torvalds 71671da177e4SLinus Torvalds /* 71681da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 71692a4317c5SJeff Layton struct nfs4_client_reclaim * 71706b189105SScott Mayhew nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) 71711da177e4SLinus Torvalds { 71721da177e4SLinus Torvalds unsigned int strhashval; 71731da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 71741da177e4SLinus Torvalds 7175dd5e3fbcSChuck Lever trace_nfsd_clid_find(nn, name.len, name.data); 71761da177e4SLinus Torvalds 71776b189105SScott Mayhew strhashval = clientstr_hashval(name); 717852e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 71796b189105SScott Mayhew if (compare_blob(&crp->cr_name, &name) == 0) { 71801da177e4SLinus Torvalds return crp; 71811da177e4SLinus Torvalds } 71821da177e4SLinus Torvalds } 71831da177e4SLinus Torvalds return NULL; 71841da177e4SLinus Torvalds } 71851da177e4SLinus Torvalds 71861da177e4SLinus Torvalds /* 71871da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 71881da177e4SLinus Torvalds */ 7189b37ad28bSAl Viro __be32 71900fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 71910fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 71920fe492dbSTrond Myklebust struct nfsd_net *nn) 71931da177e4SLinus Torvalds { 71940fe492dbSTrond Myklebust __be32 status; 7195a52d726bSJeff Layton 7196a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 7197b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 71980fe492dbSTrond Myklebust if (status) 7199a52d726bSJeff Layton return nfserr_reclaim_bad; 7200a52d726bSJeff Layton 72013b3e7b72SJeff Layton if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) 72023b3e7b72SJeff Layton return nfserr_no_grace; 72033b3e7b72SJeff Layton 72040fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 72050fe492dbSTrond Myklebust return nfserr_reclaim_bad; 72060fe492dbSTrond Myklebust 72070fe492dbSTrond Myklebust return nfs_ok; 72081da177e4SLinus Torvalds } 72091da177e4SLinus Torvalds 721065178db4SBryan Schumaker #ifdef CONFIG_NFSD_FAULT_INJECTION 7211016200c3SJeff Layton static inline void 7212016200c3SJeff Layton put_client(struct nfs4_client *clp) 7213016200c3SJeff Layton { 721414ed14ccSJ. Bruce Fields atomic_dec(&clp->cl_rpc_users); 7215016200c3SJeff Layton } 7216016200c3SJeff Layton 7217285abdeeSJeff Layton static struct nfs4_client * 7218285abdeeSJeff Layton nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) 7219285abdeeSJeff Layton { 7220285abdeeSJeff Layton struct nfs4_client *clp; 7221285abdeeSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7222285abdeeSJeff Layton nfsd_net_id); 7223285abdeeSJeff Layton 7224285abdeeSJeff Layton if (!nfsd_netns_ready(nn)) 7225285abdeeSJeff Layton return NULL; 7226285abdeeSJeff Layton 7227285abdeeSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 7228285abdeeSJeff Layton if (memcmp(&clp->cl_addr, addr, addr_size) == 0) 7229285abdeeSJeff Layton return clp; 7230285abdeeSJeff Layton } 7231285abdeeSJeff Layton return NULL; 7232285abdeeSJeff Layton } 7233285abdeeSJeff Layton 72347ec0e36fSJeff Layton u64 7235285abdeeSJeff Layton nfsd_inject_print_clients(void) 72367ec0e36fSJeff Layton { 72377ec0e36fSJeff Layton struct nfs4_client *clp; 72387ec0e36fSJeff Layton u64 count = 0; 72397ec0e36fSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 72407ec0e36fSJeff Layton nfsd_net_id); 72417ec0e36fSJeff Layton char buf[INET6_ADDRSTRLEN]; 72427ec0e36fSJeff Layton 72437ec0e36fSJeff Layton if (!nfsd_netns_ready(nn)) 72447ec0e36fSJeff Layton return 0; 72457ec0e36fSJeff Layton 72467ec0e36fSJeff Layton spin_lock(&nn->client_lock); 72477ec0e36fSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 72487ec0e36fSJeff Layton rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 72497ec0e36fSJeff Layton pr_info("NFS Client: %s\n", buf); 72507ec0e36fSJeff Layton ++count; 72517ec0e36fSJeff Layton } 72527ec0e36fSJeff Layton spin_unlock(&nn->client_lock); 72537ec0e36fSJeff Layton 72547ec0e36fSJeff Layton return count; 72557ec0e36fSJeff Layton } 725665178db4SBryan Schumaker 7257a0926d15SJeff Layton u64 7258285abdeeSJeff Layton nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) 7259a0926d15SJeff Layton { 7260a0926d15SJeff Layton u64 count = 0; 7261a0926d15SJeff Layton struct nfs4_client *clp; 7262a0926d15SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7263a0926d15SJeff Layton nfsd_net_id); 7264a0926d15SJeff Layton 7265a0926d15SJeff Layton if (!nfsd_netns_ready(nn)) 7266a0926d15SJeff Layton return count; 7267a0926d15SJeff Layton 7268a0926d15SJeff Layton spin_lock(&nn->client_lock); 7269a0926d15SJeff Layton clp = nfsd_find_client(addr, addr_size); 7270a0926d15SJeff Layton if (clp) { 7271a0926d15SJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) 7272a0926d15SJeff Layton ++count; 7273a0926d15SJeff Layton else 7274a0926d15SJeff Layton clp = NULL; 7275a0926d15SJeff Layton } 7276a0926d15SJeff Layton spin_unlock(&nn->client_lock); 7277a0926d15SJeff Layton 7278a0926d15SJeff Layton if (clp) 7279a0926d15SJeff Layton expire_client(clp); 7280a0926d15SJeff Layton 7281a0926d15SJeff Layton return count; 7282a0926d15SJeff Layton } 7283a0926d15SJeff Layton 728469fc9edfSJeff Layton u64 7285285abdeeSJeff Layton nfsd_inject_forget_clients(u64 max) 728669fc9edfSJeff Layton { 728769fc9edfSJeff Layton u64 count = 0; 728869fc9edfSJeff Layton struct nfs4_client *clp, *next; 728969fc9edfSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 729069fc9edfSJeff Layton nfsd_net_id); 729169fc9edfSJeff Layton LIST_HEAD(reaplist); 729269fc9edfSJeff Layton 729369fc9edfSJeff Layton if (!nfsd_netns_ready(nn)) 729469fc9edfSJeff Layton return count; 729569fc9edfSJeff Layton 729669fc9edfSJeff Layton spin_lock(&nn->client_lock); 729769fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 729869fc9edfSJeff Layton if (mark_client_expired_locked(clp) == nfs_ok) { 729969fc9edfSJeff Layton list_add(&clp->cl_lru, &reaplist); 730069fc9edfSJeff Layton if (max != 0 && ++count >= max) 730169fc9edfSJeff Layton break; 730269fc9edfSJeff Layton } 730369fc9edfSJeff Layton } 730469fc9edfSJeff Layton spin_unlock(&nn->client_lock); 730569fc9edfSJeff Layton 730669fc9edfSJeff Layton list_for_each_entry_safe(clp, next, &reaplist, cl_lru) 730769fc9edfSJeff Layton expire_client(clp); 730869fc9edfSJeff Layton 730969fc9edfSJeff Layton return count; 731069fc9edfSJeff Layton } 731169fc9edfSJeff Layton 7312184c1847SBryan Schumaker static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, 7313184c1847SBryan Schumaker const char *type) 7314184c1847SBryan Schumaker { 7315184c1847SBryan Schumaker char buf[INET6_ADDRSTRLEN]; 73160a5c33e2SBryan Schumaker rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); 7317184c1847SBryan Schumaker printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); 7318184c1847SBryan Schumaker } 7319184c1847SBryan Schumaker 7320016200c3SJeff Layton static void 7321016200c3SJeff Layton nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, 7322016200c3SJeff Layton struct list_head *collect) 7323016200c3SJeff Layton { 7324016200c3SJeff Layton struct nfs4_client *clp = lst->st_stid.sc_client; 7325016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7326016200c3SJeff Layton nfsd_net_id); 7327016200c3SJeff Layton 7328016200c3SJeff Layton if (!collect) 7329016200c3SJeff Layton return; 7330016200c3SJeff Layton 7331016200c3SJeff Layton lockdep_assert_held(&nn->client_lock); 733214ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 7333016200c3SJeff Layton list_add(&lst->st_locks, collect); 7334016200c3SJeff Layton } 7335016200c3SJeff Layton 73363c87b9b7STrond Myklebust static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, 73373738d50eSJeff Layton struct list_head *collect, 7338e8568739SJeff Layton bool (*func)(struct nfs4_ol_stateid *)) 7339fc29171fSBryan Schumaker { 7340fc29171fSBryan Schumaker struct nfs4_openowner *oop; 7341fc29171fSBryan Schumaker struct nfs4_ol_stateid *stp, *st_next; 73423c87b9b7STrond Myklebust struct nfs4_ol_stateid *lst, *lst_next; 7343fc29171fSBryan Schumaker u64 count = 0; 7344fc29171fSBryan Schumaker 7345016200c3SJeff Layton spin_lock(&clp->cl_lock); 7346fc29171fSBryan Schumaker list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { 73473c87b9b7STrond Myklebust list_for_each_entry_safe(stp, st_next, 73483c87b9b7STrond Myklebust &oop->oo_owner.so_stateids, st_perstateowner) { 73493c87b9b7STrond Myklebust list_for_each_entry_safe(lst, lst_next, 73503c87b9b7STrond Myklebust &stp->st_locks, st_locks) { 73513738d50eSJeff Layton if (func) { 7352e8568739SJeff Layton if (func(lst)) 7353016200c3SJeff Layton nfsd_inject_add_lock_to_list(lst, 73543738d50eSJeff Layton collect); 73553738d50eSJeff Layton } 7356016200c3SJeff Layton ++count; 7357016200c3SJeff Layton /* 7358016200c3SJeff Layton * Despite the fact that these functions deal 7359016200c3SJeff Layton * with 64-bit integers for "count", we must 7360016200c3SJeff Layton * ensure that it doesn't blow up the 736114ed14ccSJ. Bruce Fields * clp->cl_rpc_users. Throw a warning if we 7362016200c3SJeff Layton * start to approach INT_MAX here. 7363016200c3SJeff Layton */ 7364016200c3SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 7365016200c3SJeff Layton if (count == max) 7366016200c3SJeff Layton goto out; 7367fc29171fSBryan Schumaker } 7368fc29171fSBryan Schumaker } 7369fc29171fSBryan Schumaker } 7370016200c3SJeff Layton out: 7371016200c3SJeff Layton spin_unlock(&clp->cl_lock); 7372fc29171fSBryan Schumaker 7373fc29171fSBryan Schumaker return count; 7374fc29171fSBryan Schumaker } 7375fc29171fSBryan Schumaker 7376016200c3SJeff Layton static u64 7377016200c3SJeff Layton nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, 7378016200c3SJeff Layton u64 max) 7379fc29171fSBryan Schumaker { 7380016200c3SJeff Layton return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); 7381fc29171fSBryan Schumaker } 7382fc29171fSBryan Schumaker 7383016200c3SJeff Layton static u64 7384016200c3SJeff Layton nfsd_print_client_locks(struct nfs4_client *clp) 7385184c1847SBryan Schumaker { 7386016200c3SJeff Layton u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); 7387184c1847SBryan Schumaker nfsd_print_count(clp, count, "locked files"); 7388184c1847SBryan Schumaker return count; 7389184c1847SBryan Schumaker } 7390184c1847SBryan Schumaker 7391016200c3SJeff Layton u64 7392285abdeeSJeff Layton nfsd_inject_print_locks(void) 7393016200c3SJeff Layton { 7394016200c3SJeff Layton struct nfs4_client *clp; 7395016200c3SJeff Layton u64 count = 0; 7396016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7397016200c3SJeff Layton nfsd_net_id); 7398016200c3SJeff Layton 7399016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 7400016200c3SJeff Layton return 0; 7401016200c3SJeff Layton 7402016200c3SJeff Layton spin_lock(&nn->client_lock); 7403016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 7404016200c3SJeff Layton count += nfsd_print_client_locks(clp); 7405016200c3SJeff Layton spin_unlock(&nn->client_lock); 7406016200c3SJeff Layton 7407016200c3SJeff Layton return count; 7408016200c3SJeff Layton } 7409016200c3SJeff Layton 7410016200c3SJeff Layton static void 7411016200c3SJeff Layton nfsd_reap_locks(struct list_head *reaplist) 7412016200c3SJeff Layton { 7413016200c3SJeff Layton struct nfs4_client *clp; 7414016200c3SJeff Layton struct nfs4_ol_stateid *stp, *next; 7415016200c3SJeff Layton 7416016200c3SJeff Layton list_for_each_entry_safe(stp, next, reaplist, st_locks) { 7417016200c3SJeff Layton list_del_init(&stp->st_locks); 7418016200c3SJeff Layton clp = stp->st_stid.sc_client; 7419016200c3SJeff Layton nfs4_put_stid(&stp->st_stid); 7420016200c3SJeff Layton put_client(clp); 7421016200c3SJeff Layton } 7422016200c3SJeff Layton } 7423016200c3SJeff Layton 7424016200c3SJeff Layton u64 7425285abdeeSJeff Layton nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) 7426016200c3SJeff Layton { 7427016200c3SJeff Layton unsigned int count = 0; 7428016200c3SJeff Layton struct nfs4_client *clp; 7429016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7430016200c3SJeff Layton nfsd_net_id); 7431016200c3SJeff Layton LIST_HEAD(reaplist); 7432016200c3SJeff Layton 7433016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 7434016200c3SJeff Layton return count; 7435016200c3SJeff Layton 7436016200c3SJeff Layton spin_lock(&nn->client_lock); 7437016200c3SJeff Layton clp = nfsd_find_client(addr, addr_size); 7438016200c3SJeff Layton if (clp) 7439016200c3SJeff Layton count = nfsd_collect_client_locks(clp, &reaplist, 0); 7440016200c3SJeff Layton spin_unlock(&nn->client_lock); 7441016200c3SJeff Layton nfsd_reap_locks(&reaplist); 7442016200c3SJeff Layton return count; 7443016200c3SJeff Layton } 7444016200c3SJeff Layton 7445016200c3SJeff Layton u64 7446285abdeeSJeff Layton nfsd_inject_forget_locks(u64 max) 7447016200c3SJeff Layton { 7448016200c3SJeff Layton u64 count = 0; 7449016200c3SJeff Layton struct nfs4_client *clp; 7450016200c3SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 7451016200c3SJeff Layton nfsd_net_id); 7452016200c3SJeff Layton LIST_HEAD(reaplist); 7453016200c3SJeff Layton 7454016200c3SJeff Layton if (!nfsd_netns_ready(nn)) 7455016200c3SJeff Layton return count; 7456016200c3SJeff Layton 7457016200c3SJeff Layton spin_lock(&nn->client_lock); 7458016200c3SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 7459016200c3SJeff Layton count += nfsd_collect_client_locks(clp, &reaplist, max - count); 7460016200c3SJeff Layton if (max != 0 && count >= max) 7461016200c3SJeff Layton break; 7462016200c3SJeff Layton } 7463016200c3SJeff Layton spin_unlock(&nn->client_lock); 7464016200c3SJeff Layton nfsd_reap_locks(&reaplist); 7465016200c3SJeff Layton return count; 7466016200c3SJeff Layton } 7467016200c3SJeff Layton 746882e05efaSJeff Layton static u64 746982e05efaSJeff Layton nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, 747082e05efaSJeff Layton struct list_head *collect, 747182e05efaSJeff Layton void (*func)(struct nfs4_openowner *)) 74724dbdbda8SBryan Schumaker { 74734dbdbda8SBryan Schumaker struct nfs4_openowner *oop, *next; 747482e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 747582e05efaSJeff Layton nfsd_net_id); 74764dbdbda8SBryan Schumaker u64 count = 0; 74774dbdbda8SBryan Schumaker 747882e05efaSJeff Layton lockdep_assert_held(&nn->client_lock); 747982e05efaSJeff Layton 748082e05efaSJeff Layton spin_lock(&clp->cl_lock); 74814dbdbda8SBryan Schumaker list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { 748282e05efaSJeff Layton if (func) { 74834dbdbda8SBryan Schumaker func(oop); 748482e05efaSJeff Layton if (collect) { 748514ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 748682e05efaSJeff Layton list_add(&oop->oo_perclient, collect); 748782e05efaSJeff Layton } 748882e05efaSJeff Layton } 748982e05efaSJeff Layton ++count; 749082e05efaSJeff Layton /* 749182e05efaSJeff Layton * Despite the fact that these functions deal with 749282e05efaSJeff Layton * 64-bit integers for "count", we must ensure that 749314ed14ccSJ. Bruce Fields * it doesn't blow up the clp->cl_rpc_users. Throw a 749482e05efaSJeff Layton * warning if we start to approach INT_MAX here. 749582e05efaSJeff Layton */ 749682e05efaSJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 749782e05efaSJeff Layton if (count == max) 74984dbdbda8SBryan Schumaker break; 74994dbdbda8SBryan Schumaker } 750082e05efaSJeff Layton spin_unlock(&clp->cl_lock); 75014dbdbda8SBryan Schumaker 75024dbdbda8SBryan Schumaker return count; 75034dbdbda8SBryan Schumaker } 75044dbdbda8SBryan Schumaker 750582e05efaSJeff Layton static u64 750682e05efaSJeff Layton nfsd_print_client_openowners(struct nfs4_client *clp) 75074dbdbda8SBryan Schumaker { 750882e05efaSJeff Layton u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); 750982e05efaSJeff Layton 751082e05efaSJeff Layton nfsd_print_count(clp, count, "openowners"); 751182e05efaSJeff Layton return count; 75124dbdbda8SBryan Schumaker } 75134dbdbda8SBryan Schumaker 751482e05efaSJeff Layton static u64 751582e05efaSJeff Layton nfsd_collect_client_openowners(struct nfs4_client *clp, 751682e05efaSJeff Layton struct list_head *collect, u64 max) 7517184c1847SBryan Schumaker { 751882e05efaSJeff Layton return nfsd_foreach_client_openowner(clp, max, collect, 751982e05efaSJeff Layton unhash_openowner_locked); 752082e05efaSJeff Layton } 752182e05efaSJeff Layton 752282e05efaSJeff Layton u64 7523285abdeeSJeff Layton nfsd_inject_print_openowners(void) 752482e05efaSJeff Layton { 752582e05efaSJeff Layton struct nfs4_client *clp; 752682e05efaSJeff Layton u64 count = 0; 752782e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 752882e05efaSJeff Layton nfsd_net_id); 752982e05efaSJeff Layton 753082e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 753182e05efaSJeff Layton return 0; 753282e05efaSJeff Layton 753382e05efaSJeff Layton spin_lock(&nn->client_lock); 753482e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 753582e05efaSJeff Layton count += nfsd_print_client_openowners(clp); 753682e05efaSJeff Layton spin_unlock(&nn->client_lock); 753782e05efaSJeff Layton 753882e05efaSJeff Layton return count; 753982e05efaSJeff Layton } 754082e05efaSJeff Layton 754182e05efaSJeff Layton static void 754282e05efaSJeff Layton nfsd_reap_openowners(struct list_head *reaplist) 754382e05efaSJeff Layton { 754482e05efaSJeff Layton struct nfs4_client *clp; 754582e05efaSJeff Layton struct nfs4_openowner *oop, *next; 754682e05efaSJeff Layton 754782e05efaSJeff Layton list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { 754882e05efaSJeff Layton list_del_init(&oop->oo_perclient); 754982e05efaSJeff Layton clp = oop->oo_owner.so_client; 755082e05efaSJeff Layton release_openowner(oop); 755182e05efaSJeff Layton put_client(clp); 755282e05efaSJeff Layton } 755382e05efaSJeff Layton } 755482e05efaSJeff Layton 755582e05efaSJeff Layton u64 7556285abdeeSJeff Layton nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, 7557285abdeeSJeff Layton size_t addr_size) 755882e05efaSJeff Layton { 755982e05efaSJeff Layton unsigned int count = 0; 756082e05efaSJeff Layton struct nfs4_client *clp; 756182e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 756282e05efaSJeff Layton nfsd_net_id); 756382e05efaSJeff Layton LIST_HEAD(reaplist); 756482e05efaSJeff Layton 756582e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 756682e05efaSJeff Layton return count; 756782e05efaSJeff Layton 756882e05efaSJeff Layton spin_lock(&nn->client_lock); 756982e05efaSJeff Layton clp = nfsd_find_client(addr, addr_size); 757082e05efaSJeff Layton if (clp) 757182e05efaSJeff Layton count = nfsd_collect_client_openowners(clp, &reaplist, 0); 757282e05efaSJeff Layton spin_unlock(&nn->client_lock); 757382e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 757482e05efaSJeff Layton return count; 757582e05efaSJeff Layton } 757682e05efaSJeff Layton 757782e05efaSJeff Layton u64 7578285abdeeSJeff Layton nfsd_inject_forget_openowners(u64 max) 757982e05efaSJeff Layton { 758082e05efaSJeff Layton u64 count = 0; 758182e05efaSJeff Layton struct nfs4_client *clp; 758282e05efaSJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 758382e05efaSJeff Layton nfsd_net_id); 758482e05efaSJeff Layton LIST_HEAD(reaplist); 758582e05efaSJeff Layton 758682e05efaSJeff Layton if (!nfsd_netns_ready(nn)) 758782e05efaSJeff Layton return count; 758882e05efaSJeff Layton 758982e05efaSJeff Layton spin_lock(&nn->client_lock); 759082e05efaSJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 759182e05efaSJeff Layton count += nfsd_collect_client_openowners(clp, &reaplist, 759282e05efaSJeff Layton max - count); 759382e05efaSJeff Layton if (max != 0 && count >= max) 759482e05efaSJeff Layton break; 759582e05efaSJeff Layton } 759682e05efaSJeff Layton spin_unlock(&nn->client_lock); 759782e05efaSJeff Layton nfsd_reap_openowners(&reaplist); 7598184c1847SBryan Schumaker return count; 7599184c1847SBryan Schumaker } 7600184c1847SBryan Schumaker 7601269de30fSBryan Schumaker static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, 7602269de30fSBryan Schumaker struct list_head *victims) 7603269de30fSBryan Schumaker { 7604269de30fSBryan Schumaker struct nfs4_delegation *dp, *next; 760598d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 760698d5c7c5SJeff Layton nfsd_net_id); 7607269de30fSBryan Schumaker u64 count = 0; 7608269de30fSBryan Schumaker 760998d5c7c5SJeff Layton lockdep_assert_held(&nn->client_lock); 761098d5c7c5SJeff Layton 761198d5c7c5SJeff Layton spin_lock(&state_lock); 7612269de30fSBryan Schumaker list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { 7613dff1399fSJeff Layton if (victims) { 7614dff1399fSJeff Layton /* 7615dff1399fSJeff Layton * It's not safe to mess with delegations that have a 7616dff1399fSJeff Layton * non-zero dl_time. They might have already been broken 7617dff1399fSJeff Layton * and could be processed by the laundromat outside of 7618dff1399fSJeff Layton * the state_lock. Just leave them be. 7619dff1399fSJeff Layton */ 7620dff1399fSJeff Layton if (dp->dl_time != 0) 7621dff1399fSJeff Layton continue; 7622dff1399fSJeff Layton 762314ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 76243fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 762542690676SJeff Layton list_add(&dp->dl_recall_lru, victims); 7626dff1399fSJeff Layton } 762798d5c7c5SJeff Layton ++count; 762898d5c7c5SJeff Layton /* 762998d5c7c5SJeff Layton * Despite the fact that these functions deal with 763098d5c7c5SJeff Layton * 64-bit integers for "count", we must ensure that 763114ed14ccSJ. Bruce Fields * it doesn't blow up the clp->cl_rpc_users. Throw a 763298d5c7c5SJeff Layton * warning if we start to approach INT_MAX here. 763398d5c7c5SJeff Layton */ 763498d5c7c5SJeff Layton WARN_ON_ONCE(count == (INT_MAX / 2)); 763598d5c7c5SJeff Layton if (count == max) 7636269de30fSBryan Schumaker break; 7637269de30fSBryan Schumaker } 763898d5c7c5SJeff Layton spin_unlock(&state_lock); 7639269de30fSBryan Schumaker return count; 7640269de30fSBryan Schumaker } 7641269de30fSBryan Schumaker 764298d5c7c5SJeff Layton static u64 764398d5c7c5SJeff Layton nfsd_print_client_delegations(struct nfs4_client *clp) 7644269de30fSBryan Schumaker { 764598d5c7c5SJeff Layton u64 count = nfsd_find_all_delegations(clp, 0, NULL); 7646184c1847SBryan Schumaker 7647184c1847SBryan Schumaker nfsd_print_count(clp, count, "delegations"); 7648184c1847SBryan Schumaker return count; 7649184c1847SBryan Schumaker } 7650184c1847SBryan Schumaker 765198d5c7c5SJeff Layton u64 7652285abdeeSJeff Layton nfsd_inject_print_delegations(void) 765398d5c7c5SJeff Layton { 765498d5c7c5SJeff Layton struct nfs4_client *clp; 765598d5c7c5SJeff Layton u64 count = 0; 765698d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 765798d5c7c5SJeff Layton nfsd_net_id); 765898d5c7c5SJeff Layton 765998d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 766098d5c7c5SJeff Layton return 0; 766198d5c7c5SJeff Layton 766298d5c7c5SJeff Layton spin_lock(&nn->client_lock); 766398d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) 766498d5c7c5SJeff Layton count += nfsd_print_client_delegations(clp); 766598d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 766698d5c7c5SJeff Layton 766798d5c7c5SJeff Layton return count; 766898d5c7c5SJeff Layton } 766998d5c7c5SJeff Layton 767098d5c7c5SJeff Layton static void 767198d5c7c5SJeff Layton nfsd_forget_delegations(struct list_head *reaplist) 767298d5c7c5SJeff Layton { 767398d5c7c5SJeff Layton struct nfs4_client *clp; 767498d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 767598d5c7c5SJeff Layton 767698d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 767798d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 767898d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 767998d5c7c5SJeff Layton revoke_delegation(dp); 768098d5c7c5SJeff Layton put_client(clp); 768198d5c7c5SJeff Layton } 768298d5c7c5SJeff Layton } 768398d5c7c5SJeff Layton 768498d5c7c5SJeff Layton u64 7685285abdeeSJeff Layton nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, 7686285abdeeSJeff Layton size_t addr_size) 768798d5c7c5SJeff Layton { 768898d5c7c5SJeff Layton u64 count = 0; 768998d5c7c5SJeff Layton struct nfs4_client *clp; 769098d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 769198d5c7c5SJeff Layton nfsd_net_id); 769298d5c7c5SJeff Layton LIST_HEAD(reaplist); 769398d5c7c5SJeff Layton 769498d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 769598d5c7c5SJeff Layton return count; 769698d5c7c5SJeff Layton 769798d5c7c5SJeff Layton spin_lock(&nn->client_lock); 769898d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 769998d5c7c5SJeff Layton if (clp) 770098d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 770198d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 770298d5c7c5SJeff Layton 770398d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 770498d5c7c5SJeff Layton return count; 770598d5c7c5SJeff Layton } 770698d5c7c5SJeff Layton 770798d5c7c5SJeff Layton u64 7708285abdeeSJeff Layton nfsd_inject_forget_delegations(u64 max) 770998d5c7c5SJeff Layton { 771098d5c7c5SJeff Layton u64 count = 0; 771198d5c7c5SJeff Layton struct nfs4_client *clp; 771298d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 771398d5c7c5SJeff Layton nfsd_net_id); 771498d5c7c5SJeff Layton LIST_HEAD(reaplist); 771598d5c7c5SJeff Layton 771698d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 771798d5c7c5SJeff Layton return count; 771898d5c7c5SJeff Layton 771998d5c7c5SJeff Layton spin_lock(&nn->client_lock); 772098d5c7c5SJeff Layton list_for_each_entry(clp, &nn->client_lru, cl_lru) { 772198d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 772298d5c7c5SJeff Layton if (max != 0 && count >= max) 772398d5c7c5SJeff Layton break; 772498d5c7c5SJeff Layton } 772598d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 772698d5c7c5SJeff Layton nfsd_forget_delegations(&reaplist); 772798d5c7c5SJeff Layton return count; 772898d5c7c5SJeff Layton } 772998d5c7c5SJeff Layton 773098d5c7c5SJeff Layton static void 773198d5c7c5SJeff Layton nfsd_recall_delegations(struct list_head *reaplist) 773298d5c7c5SJeff Layton { 773398d5c7c5SJeff Layton struct nfs4_client *clp; 773498d5c7c5SJeff Layton struct nfs4_delegation *dp, *next; 773598d5c7c5SJeff Layton 773698d5c7c5SJeff Layton list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { 773798d5c7c5SJeff Layton list_del_init(&dp->dl_recall_lru); 773898d5c7c5SJeff Layton clp = dp->dl_stid.sc_client; 7739dd5e3fbcSChuck Lever 7740dd5e3fbcSChuck Lever trace_nfsd_deleg_recall(&dp->dl_stid.sc_stateid); 7741dd5e3fbcSChuck Lever 774298d5c7c5SJeff Layton /* 774398d5c7c5SJeff Layton * We skipped all entries that had a zero dl_time before, 774498d5c7c5SJeff Layton * so we can now reset the dl_time back to 0. If a delegation 774598d5c7c5SJeff Layton * break comes in now, then it won't make any difference since 774698d5c7c5SJeff Layton * we're recalling it either way. 774798d5c7c5SJeff Layton */ 774898d5c7c5SJeff Layton spin_lock(&state_lock); 774998d5c7c5SJeff Layton dp->dl_time = 0; 775098d5c7c5SJeff Layton spin_unlock(&state_lock); 775198d5c7c5SJeff Layton nfsd_break_one_deleg(dp); 775298d5c7c5SJeff Layton put_client(clp); 775398d5c7c5SJeff Layton } 775498d5c7c5SJeff Layton } 775598d5c7c5SJeff Layton 775698d5c7c5SJeff Layton u64 7757285abdeeSJeff Layton nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, 775898d5c7c5SJeff Layton size_t addr_size) 775998d5c7c5SJeff Layton { 776098d5c7c5SJeff Layton u64 count = 0; 776198d5c7c5SJeff Layton struct nfs4_client *clp; 776298d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 776398d5c7c5SJeff Layton nfsd_net_id); 776498d5c7c5SJeff Layton LIST_HEAD(reaplist); 776598d5c7c5SJeff Layton 776698d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 776798d5c7c5SJeff Layton return count; 776898d5c7c5SJeff Layton 776998d5c7c5SJeff Layton spin_lock(&nn->client_lock); 777098d5c7c5SJeff Layton clp = nfsd_find_client(addr, addr_size); 777198d5c7c5SJeff Layton if (clp) 777298d5c7c5SJeff Layton count = nfsd_find_all_delegations(clp, 0, &reaplist); 777398d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 777498d5c7c5SJeff Layton 777598d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 777698d5c7c5SJeff Layton return count; 777798d5c7c5SJeff Layton } 777898d5c7c5SJeff Layton 777998d5c7c5SJeff Layton u64 7780285abdeeSJeff Layton nfsd_inject_recall_delegations(u64 max) 778198d5c7c5SJeff Layton { 778298d5c7c5SJeff Layton u64 count = 0; 778398d5c7c5SJeff Layton struct nfs4_client *clp, *next; 778498d5c7c5SJeff Layton struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, 778598d5c7c5SJeff Layton nfsd_net_id); 778698d5c7c5SJeff Layton LIST_HEAD(reaplist); 778798d5c7c5SJeff Layton 778898d5c7c5SJeff Layton if (!nfsd_netns_ready(nn)) 778998d5c7c5SJeff Layton return count; 779098d5c7c5SJeff Layton 779198d5c7c5SJeff Layton spin_lock(&nn->client_lock); 779298d5c7c5SJeff Layton list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { 779398d5c7c5SJeff Layton count += nfsd_find_all_delegations(clp, max - count, &reaplist); 779498d5c7c5SJeff Layton if (max != 0 && ++count >= max) 779598d5c7c5SJeff Layton break; 779698d5c7c5SJeff Layton } 779798d5c7c5SJeff Layton spin_unlock(&nn->client_lock); 779898d5c7c5SJeff Layton nfsd_recall_delegations(&reaplist); 779998d5c7c5SJeff Layton return count; 780098d5c7c5SJeff Layton } 780165178db4SBryan Schumaker #endif /* CONFIG_NFSD_FAULT_INJECTION */ 780265178db4SBryan Schumaker 7803c2f1a551SMeelap Shah /* 7804c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 7805c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 7806c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 7807c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 7808c2f1a551SMeelap Shah * 7809c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 7810c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 7811c2f1a551SMeelap Shah */ 7812c2f1a551SMeelap Shah static void 7813c2f1a551SMeelap Shah set_max_delegations(void) 7814c2f1a551SMeelap Shah { 7815c2f1a551SMeelap Shah /* 7816c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 7817c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 7818c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 7819c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 7820c2f1a551SMeelap Shah */ 7821c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 7822c2f1a551SMeelap Shah } 7823c2f1a551SMeelap Shah 7824d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 78258daae4dcSStanislav Kinsbursky { 78268daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 78278daae4dcSStanislav Kinsbursky int i; 78288daae4dcSStanislav Kinsbursky 78296da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 78306da2ec56SKees Cook sizeof(struct list_head), 78316da2ec56SKees Cook GFP_KERNEL); 78328daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 7833382a62e7SStanislav Kinsbursky goto err; 78346da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 78356da2ec56SKees Cook sizeof(struct list_head), 78366da2ec56SKees Cook GFP_KERNEL); 78370a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 78380a7ec377SStanislav Kinsbursky goto err_unconf_id; 78396da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 78406da2ec56SKees Cook sizeof(struct list_head), 78416da2ec56SKees Cook GFP_KERNEL); 78421872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 78431872de0eSStanislav Kinsbursky goto err_sessionid; 78448daae4dcSStanislav Kinsbursky 7845382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 78468daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 78470a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 7848382a62e7SStanislav Kinsbursky } 78491872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 78501872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 7851382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 7852a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 78539cc76801SArnd Bergmann nn->boot_time = ktime_get_real_seconds(); 785481833de1SVasily Averin nn->grace_ended = false; 785581833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 785681833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 78575ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 785873758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 7859e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 7860c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 7861e0639dc5SOlga Kornievskaia spin_lock_init(&nn->s2s_cp_lock); 7862e0639dc5SOlga Kornievskaia idr_init(&nn->s2s_cp_stateids); 78638daae4dcSStanislav Kinsbursky 78640cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 78650cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 78660cc11a61SJeff Layton 786709121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 7868d85ed443SStanislav Kinsbursky get_net(net); 786909121281SStanislav Kinsbursky 78708daae4dcSStanislav Kinsbursky return 0; 7871382a62e7SStanislav Kinsbursky 78721872de0eSStanislav Kinsbursky err_sessionid: 78739b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 78740a7ec377SStanislav Kinsbursky err_unconf_id: 78750a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 7876382a62e7SStanislav Kinsbursky err: 7877382a62e7SStanislav Kinsbursky return -ENOMEM; 78788daae4dcSStanislav Kinsbursky } 78798daae4dcSStanislav Kinsbursky 78808daae4dcSStanislav Kinsbursky static void 78814dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 78828daae4dcSStanislav Kinsbursky { 78838daae4dcSStanislav Kinsbursky int i; 78848daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 78858daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 78868daae4dcSStanislav Kinsbursky 78878daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 78888daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 78898daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 78908daae4dcSStanislav Kinsbursky destroy_client(clp); 78918daae4dcSStanislav Kinsbursky } 78928daae4dcSStanislav Kinsbursky } 7893a99454aaSStanislav Kinsbursky 789468ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 789568ef3bc3SJeff Layton 78962b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 78972b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 78982b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 7899a99454aaSStanislav Kinsbursky destroy_client(clp); 7900a99454aaSStanislav Kinsbursky } 79012b905635SKinglong Mee } 7902a99454aaSStanislav Kinsbursky 79031872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 79040a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 79058daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 79064dce0ac9SStanislav Kinsbursky put_net(net); 79078daae4dcSStanislav Kinsbursky } 79088daae4dcSStanislav Kinsbursky 7909f252bc68SStanislav Kinsbursky int 7910d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 7911ac4d8ff2SNeilBrown { 79125e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 7913b5a1a81eSJ. Bruce Fields int ret; 7914b5a1a81eSJ. Bruce Fields 7915681370f4SJ. Bruce Fields ret = get_nfsdfs(net); 79168daae4dcSStanislav Kinsbursky if (ret) 79178daae4dcSStanislav Kinsbursky return ret; 7918681370f4SJ. Bruce Fields ret = nfs4_state_create_net(net); 7919681370f4SJ. Bruce Fields if (ret) { 7920681370f4SJ. Bruce Fields mntput(nn->nfsd_mnt); 7921681370f4SJ. Bruce Fields return ret; 7922681370f4SJ. Bruce Fields } 7923d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 7924d4318acdSJeff Layton nfsd4_client_tracking_init(net); 7925362063a5SScott Mayhew if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) 7926362063a5SScott Mayhew goto skip_grace; 792720b7d86fSArnd Bergmann printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", 79287e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 7929dd5e3fbcSChuck Lever trace_nfsd_grace_start(nn); 79305284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 7931d85ed443SStanislav Kinsbursky return 0; 7932362063a5SScott Mayhew 7933362063a5SScott Mayhew skip_grace: 7934362063a5SScott Mayhew printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n", 7935362063a5SScott Mayhew net->ns.inum); 7936362063a5SScott Mayhew queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ); 7937362063a5SScott Mayhew nfsd4_end_grace(nn); 7938362063a5SScott Mayhew return 0; 7939a6d6b781SJeff Layton } 7940d85ed443SStanislav Kinsbursky 7941d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 7942d85ed443SStanislav Kinsbursky 7943d85ed443SStanislav Kinsbursky int 7944d85ed443SStanislav Kinsbursky nfs4_state_start(void) 7945d85ed443SStanislav Kinsbursky { 7946d85ed443SStanislav Kinsbursky int ret; 7947d85ed443SStanislav Kinsbursky 794851a54568SJeff Layton laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 7949a6d6b781SJeff Layton if (laundry_wq == NULL) { 7950a6d6b781SJeff Layton ret = -ENOMEM; 7951a26dd64fSChuck Lever goto out; 7952a6d6b781SJeff Layton } 7953b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 7954b5a1a81eSJ. Bruce Fields if (ret) 7955b5a1a81eSJ. Bruce Fields goto out_free_laundry; 795609121281SStanislav Kinsbursky 7957c2f1a551SMeelap Shah set_max_delegations(); 7958b5a1a81eSJ. Bruce Fields return 0; 7959d85ed443SStanislav Kinsbursky 7960b5a1a81eSJ. Bruce Fields out_free_laundry: 7961b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 7962a26dd64fSChuck Lever out: 7963b5a1a81eSJ. Bruce Fields return ret; 79641da177e4SLinus Torvalds } 79651da177e4SLinus Torvalds 7966f252bc68SStanislav Kinsbursky void 79674dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 79681da177e4SLinus Torvalds { 79691da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 79701da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 79714dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 79721da177e4SLinus Torvalds 79734dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 79744dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 7975ac55fdc4SJeff Layton 79761da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 7977cdc97505SBenny Halevy spin_lock(&state_lock); 7978e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 79791da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 79803fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 798142690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 79821da177e4SLinus Torvalds } 7983cdc97505SBenny Halevy spin_unlock(&state_lock); 79841da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 79851da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 798642690676SJeff Layton list_del_init(&dp->dl_recall_lru); 79870af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 79881da177e4SLinus Torvalds } 79891da177e4SLinus Torvalds 79903320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 79914dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 7992681370f4SJ. Bruce Fields mntput(nn->nfsd_mnt); 79931da177e4SLinus Torvalds } 79941da177e4SLinus Torvalds 79951da177e4SLinus Torvalds void 79961da177e4SLinus Torvalds nfs4_state_shutdown(void) 79971da177e4SLinus Torvalds { 79985e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 7999c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 80001da177e4SLinus Torvalds } 80018b70484cSTigran Mkrtchyan 80028b70484cSTigran Mkrtchyan static void 80038b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 80048b70484cSTigran Mkrtchyan { 800551100d2bSOlga Kornievskaia if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) && 800651100d2bSOlga Kornievskaia CURRENT_STATEID(stateid)) 800737c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 80088b70484cSTigran Mkrtchyan } 80098b70484cSTigran Mkrtchyan 80108b70484cSTigran Mkrtchyan static void 80118b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 80128b70484cSTigran Mkrtchyan { 801337c593c5STigran Mkrtchyan if (cstate->minorversion) { 801437c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 801551100d2bSOlga Kornievskaia SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 801637c593c5STigran Mkrtchyan } 801737c593c5STigran Mkrtchyan } 801837c593c5STigran Mkrtchyan 801937c593c5STigran Mkrtchyan void 802037c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 802137c593c5STigran Mkrtchyan { 802251100d2bSOlga Kornievskaia CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 80238b70484cSTigran Mkrtchyan } 80248b70484cSTigran Mkrtchyan 802562cd4a59STigran Mkrtchyan /* 802662cd4a59STigran Mkrtchyan * functions to set current state id 802762cd4a59STigran Mkrtchyan */ 80288b70484cSTigran Mkrtchyan void 8029b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 8030b60e9859SChristoph Hellwig union nfsd4_op_u *u) 80319428fe1aSTigran Mkrtchyan { 8032b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 80339428fe1aSTigran Mkrtchyan } 80349428fe1aSTigran Mkrtchyan 80359428fe1aSTigran Mkrtchyan void 8036b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 8037b60e9859SChristoph Hellwig union nfsd4_op_u *u) 80388b70484cSTigran Mkrtchyan { 8039b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 80408b70484cSTigran Mkrtchyan } 80418b70484cSTigran Mkrtchyan 80428b70484cSTigran Mkrtchyan void 8043b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 8044b60e9859SChristoph Hellwig union nfsd4_op_u *u) 804562cd4a59STigran Mkrtchyan { 8046b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 804762cd4a59STigran Mkrtchyan } 804862cd4a59STigran Mkrtchyan 804962cd4a59STigran Mkrtchyan void 8050b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 8051b60e9859SChristoph Hellwig union nfsd4_op_u *u) 805262cd4a59STigran Mkrtchyan { 8053b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 805462cd4a59STigran Mkrtchyan } 805562cd4a59STigran Mkrtchyan 805662cd4a59STigran Mkrtchyan /* 805762cd4a59STigran Mkrtchyan * functions to consume current state id 805862cd4a59STigran Mkrtchyan */ 80591e97b519STigran Mkrtchyan 80601e97b519STigran Mkrtchyan void 806157832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 806257832e7bSChristoph Hellwig union nfsd4_op_u *u) 80639428fe1aSTigran Mkrtchyan { 806457832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 80659428fe1aSTigran Mkrtchyan } 80669428fe1aSTigran Mkrtchyan 80679428fe1aSTigran Mkrtchyan void 806857832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 806957832e7bSChristoph Hellwig union nfsd4_op_u *u) 80709428fe1aSTigran Mkrtchyan { 807157832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 80729428fe1aSTigran Mkrtchyan } 80739428fe1aSTigran Mkrtchyan 80749428fe1aSTigran Mkrtchyan void 807557832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 807657832e7bSChristoph Hellwig union nfsd4_op_u *u) 80771e97b519STigran Mkrtchyan { 807857832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 80791e97b519STigran Mkrtchyan } 80801e97b519STigran Mkrtchyan 80811e97b519STigran Mkrtchyan void 808257832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 808357832e7bSChristoph Hellwig union nfsd4_op_u *u) 80841e97b519STigran Mkrtchyan { 808557832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 80861e97b519STigran Mkrtchyan } 80871e97b519STigran Mkrtchyan 808862cd4a59STigran Mkrtchyan void 808957832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 809057832e7bSChristoph Hellwig union nfsd4_op_u *u) 80918b70484cSTigran Mkrtchyan { 809257832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 80938b70484cSTigran Mkrtchyan } 80948b70484cSTigran Mkrtchyan 80958b70484cSTigran Mkrtchyan void 809657832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 809757832e7bSChristoph Hellwig union nfsd4_op_u *u) 80988b70484cSTigran Mkrtchyan { 809957832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 81008b70484cSTigran Mkrtchyan } 810130813e27STigran Mkrtchyan 810230813e27STigran Mkrtchyan void 810357832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 810457832e7bSChristoph Hellwig union nfsd4_op_u *u) 810530813e27STigran Mkrtchyan { 810657832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 810730813e27STigran Mkrtchyan } 810830813e27STigran Mkrtchyan 810930813e27STigran Mkrtchyan void 811057832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 811157832e7bSChristoph Hellwig union nfsd4_op_u *u) 811230813e27STigran Mkrtchyan { 811357832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 811430813e27STigran Mkrtchyan } 8115