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 5109affa435SJ. Bruce Fields static struct nfsd_file *find_deleg_file(struct nfs4_file *f) 5119affa435SJ. Bruce Fields { 5129affa435SJ. Bruce Fields struct nfsd_file *ret = NULL; 5139affa435SJ. Bruce Fields 5149affa435SJ. Bruce Fields spin_lock(&f->fi_lock); 5159affa435SJ. Bruce Fields if (f->fi_deleg_file) 5169affa435SJ. Bruce Fields ret = nfsd_file_get(f->fi_deleg_file); 5179affa435SJ. Bruce Fields spin_unlock(&f->fi_lock); 5189affa435SJ. Bruce Fields return ret; 5199affa435SJ. Bruce Fields } 5209affa435SJ. Bruce Fields 52102a3508dSTrond Myklebust static atomic_long_t num_delegations; 522697ce9beSZhang Yanfei unsigned long max_delegations; 523ef0f3390SNeilBrown 524ef0f3390SNeilBrown /* 525ef0f3390SNeilBrown * Open owner state (share locks) 526ef0f3390SNeilBrown */ 527ef0f3390SNeilBrown 52816bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 52916bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 53016bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 53116bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 532ef0f3390SNeilBrown 533d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 534ddc04c41SJ. Bruce Fields { 535ddc04c41SJ. Bruce Fields unsigned int ret; 536ddc04c41SJ. Bruce Fields 537ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 53816bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 539ddc04c41SJ. Bruce Fields } 540ef0f3390SNeilBrown 541ef0f3390SNeilBrown /* hash table for nfs4_file */ 542ef0f3390SNeilBrown #define FILE_HASH_BITS 8 543ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 54435079582SShan Wei 545ca943217STrond Myklebust static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) 546ddc04c41SJ. Bruce Fields { 547ca943217STrond Myklebust return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); 548ca943217STrond Myklebust } 549ca943217STrond Myklebust 550ca943217STrond Myklebust static unsigned int file_hashval(struct knfsd_fh *fh) 551ca943217STrond Myklebust { 552ca943217STrond Myklebust return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); 553ca943217STrond Myklebust } 554ca943217STrond Myklebust 55589876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 556ef0f3390SNeilBrown 55712659651SJeff Layton static void 55812659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 5593477565eSJ. Bruce Fields { 5607214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5617214e860SJeff Layton 56212659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 56312659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 56412659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 56512659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 5663477565eSJ. Bruce Fields } 5673477565eSJ. Bruce Fields 56812659651SJeff Layton static __be32 56912659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 570998db52cSJ. Bruce Fields { 5717214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 5727214e860SJeff Layton 57312659651SJeff Layton /* Does this access mode make sense? */ 57412659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 57512659651SJeff Layton return nfserr_inval; 57612659651SJeff Layton 577baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 578baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 579baeb4ff0SJeff Layton return nfserr_share_denied; 580baeb4ff0SJeff Layton 58112659651SJeff Layton __nfs4_file_get_access(fp, access); 58212659651SJeff Layton return nfs_ok; 583998db52cSJ. Bruce Fields } 584998db52cSJ. Bruce Fields 585baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 586baeb4ff0SJeff Layton { 587baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 588baeb4ff0SJeff Layton if (deny) { 589baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 590baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 591baeb4ff0SJeff Layton return nfserr_inval; 592baeb4ff0SJeff Layton 593baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 594baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 595baeb4ff0SJeff Layton return nfserr_share_denied; 596baeb4ff0SJeff Layton 597baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 598baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 599baeb4ff0SJeff Layton return nfserr_share_denied; 600baeb4ff0SJeff Layton } 601baeb4ff0SJeff Layton return nfs_ok; 602baeb4ff0SJeff Layton } 603baeb4ff0SJeff Layton 604998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 605f9d7562fSJ. Bruce Fields { 606de18643dSTrond Myklebust might_lock(&fp->fi_lock); 607de18643dSTrond Myklebust 608de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 609fd4f83fdSJeff Layton struct nfsd_file *f1 = NULL; 610fd4f83fdSJeff Layton struct nfsd_file *f2 = NULL; 611de18643dSTrond Myklebust 6126d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 6130c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 6146d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 615de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 616de18643dSTrond Myklebust if (f1) 617fd4f83fdSJeff Layton nfsd_file_put(f1); 618de18643dSTrond Myklebust if (f2) 619fd4f83fdSJeff Layton nfsd_file_put(f2); 620f9d7562fSJ. Bruce Fields } 621f9d7562fSJ. Bruce Fields } 622f9d7562fSJ. Bruce Fields 62312659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 624998db52cSJ. Bruce Fields { 62512659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 62612659651SJeff Layton 62712659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 628998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 62912659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 63012659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 631998db52cSJ. Bruce Fields } 632998db52cSJ. Bruce Fields 6338287f009SSachin Bhamare /* 6348287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 6358287f009SSachin Bhamare * pNFS for proper return on close semantics. 6368287f009SSachin Bhamare * 6378287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 6388287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 6398287f009SSachin Bhamare */ 6408287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6418287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 6428287f009SSachin Bhamare { 6438287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6448287f009SSachin Bhamare 6458287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 6468287f009SSachin Bhamare if (co) { 6478287f009SSachin Bhamare co->co_client = clp; 648cff7cb2eSElena Reshetova refcount_set(&co->co_odcount, 1); 6498287f009SSachin Bhamare } 6508287f009SSachin Bhamare return co; 6518287f009SSachin Bhamare } 6528287f009SSachin Bhamare 6538287f009SSachin Bhamare static void 6548287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 6558287f009SSachin Bhamare { 6568287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 6578287f009SSachin Bhamare 6588287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 6598287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 6608287f009SSachin Bhamare } 6618287f009SSachin Bhamare 6628287f009SSachin Bhamare static inline void 6638287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 6648287f009SSachin Bhamare { 6658287f009SSachin Bhamare if (co) 666cff7cb2eSElena Reshetova refcount_inc(&co->co_odcount); 6678287f009SSachin Bhamare } 6688287f009SSachin Bhamare 6698287f009SSachin Bhamare static void 6708287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 6718287f009SSachin Bhamare { 6728287f009SSachin Bhamare struct nfs4_file *fp; 6738287f009SSachin Bhamare 6748287f009SSachin Bhamare if (!co) 6758287f009SSachin Bhamare return; 6768287f009SSachin Bhamare 6778287f009SSachin Bhamare fp = co->co_file; 678cff7cb2eSElena Reshetova if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 6798287f009SSachin Bhamare list_del(&co->co_perfile); 6808287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 6818287f009SSachin Bhamare 6828287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 6838287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 6848287f009SSachin Bhamare } 6858287f009SSachin Bhamare } 6868287f009SSachin Bhamare 6878287f009SSachin Bhamare static struct nfs4_clnt_odstate * 6888287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 6898287f009SSachin Bhamare { 6908287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 6918287f009SSachin Bhamare struct nfs4_client *cl; 6928287f009SSachin Bhamare 6938287f009SSachin Bhamare if (!new) 6948287f009SSachin Bhamare return NULL; 6958287f009SSachin Bhamare 6968287f009SSachin Bhamare cl = new->co_client; 6978287f009SSachin Bhamare 6988287f009SSachin Bhamare spin_lock(&fp->fi_lock); 6998287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 7008287f009SSachin Bhamare if (co->co_client == cl) { 7018287f009SSachin Bhamare get_clnt_odstate(co); 7028287f009SSachin Bhamare goto out; 7038287f009SSachin Bhamare } 7048287f009SSachin Bhamare } 7058287f009SSachin Bhamare co = new; 7068287f009SSachin Bhamare co->co_file = fp; 7078287f009SSachin Bhamare hash_clnt_odstate_locked(new); 7088287f009SSachin Bhamare out: 7098287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 7108287f009SSachin Bhamare return co; 7118287f009SSachin Bhamare } 7128287f009SSachin Bhamare 713d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 714d19fb70dSKinglong Mee void (*sc_free)(struct nfs4_stid *)) 715996e0938SJ. Bruce Fields { 7163abdb607SJ. Bruce Fields struct nfs4_stid *stid; 7173abdb607SJ. Bruce Fields int new_id; 7183abdb607SJ. Bruce Fields 719f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 7203abdb607SJ. Bruce Fields if (!stid) 7213abdb607SJ. Bruce Fields return NULL; 722996e0938SJ. Bruce Fields 7234770d722SJeff Layton idr_preload(GFP_KERNEL); 7244770d722SJeff Layton spin_lock(&cl->cl_lock); 72578599c42SJ. Bruce Fields /* Reserving 0 for start of file in nfsdfs "states" file: */ 72678599c42SJ. Bruce Fields new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 1, 0, GFP_NOWAIT); 7274770d722SJeff Layton spin_unlock(&cl->cl_lock); 7284770d722SJeff Layton idr_preload_end(); 729ebd6c707STejun Heo if (new_id < 0) 7303abdb607SJ. Bruce Fields goto out_free; 731d19fb70dSKinglong Mee 732d19fb70dSKinglong Mee stid->sc_free = sc_free; 7333abdb607SJ. Bruce Fields stid->sc_client = cl; 7343abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 7353abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 7363abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 737a15dfcd5SElena Reshetova refcount_set(&stid->sc_count, 1); 7389767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 739624322f1SOlga Kornievskaia INIT_LIST_HEAD(&stid->sc_cp_list); 7403abdb607SJ. Bruce Fields 741996e0938SJ. Bruce Fields /* 7423abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 7433abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 7443abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 7453abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 7463abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 7473abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 7483abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 749996e0938SJ. Bruce Fields */ 7503abdb607SJ. Bruce Fields return stid; 7513abdb607SJ. Bruce Fields out_free: 7522c44a234SWei Yongjun kmem_cache_free(slab, stid); 7533abdb607SJ. Bruce Fields return NULL; 7542a74aba7SJ. Bruce Fields } 7552a74aba7SJ. Bruce Fields 756e0639dc5SOlga Kornievskaia /* 757e0639dc5SOlga Kornievskaia * Create a unique stateid_t to represent each COPY. 758e0639dc5SOlga Kornievskaia */ 759624322f1SOlga Kornievskaia static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, 760624322f1SOlga Kornievskaia unsigned char sc_type) 761e0639dc5SOlga Kornievskaia { 762e0639dc5SOlga Kornievskaia int new_id; 763e0639dc5SOlga Kornievskaia 7649cc76801SArnd Bergmann stid->stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; 765624322f1SOlga Kornievskaia stid->stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; 766624322f1SOlga Kornievskaia stid->sc_type = sc_type; 767624322f1SOlga Kornievskaia 768e0639dc5SOlga Kornievskaia idr_preload(GFP_KERNEL); 769e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 770624322f1SOlga Kornievskaia new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT); 771624322f1SOlga Kornievskaia stid->stid.si_opaque.so_id = new_id; 772*ca9364ddSDai Ngo stid->stid.si_generation = 1; 773e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 774e0639dc5SOlga Kornievskaia idr_preload_end(); 775e0639dc5SOlga Kornievskaia if (new_id < 0) 776e0639dc5SOlga Kornievskaia return 0; 777e0639dc5SOlga Kornievskaia return 1; 778e0639dc5SOlga Kornievskaia } 779e0639dc5SOlga Kornievskaia 780624322f1SOlga Kornievskaia int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy) 781624322f1SOlga Kornievskaia { 782624322f1SOlga Kornievskaia return nfs4_init_cp_state(nn, ©->cp_stateid, NFS4_COPY_STID); 783624322f1SOlga Kornievskaia } 784624322f1SOlga Kornievskaia 785624322f1SOlga Kornievskaia struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, 786624322f1SOlga Kornievskaia struct nfs4_stid *p_stid) 787624322f1SOlga Kornievskaia { 788624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 789624322f1SOlga Kornievskaia 790624322f1SOlga Kornievskaia cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL); 791624322f1SOlga Kornievskaia if (!cps) 792624322f1SOlga Kornievskaia return NULL; 79320b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 794624322f1SOlga Kornievskaia refcount_set(&cps->cp_stateid.sc_count, 1); 795624322f1SOlga Kornievskaia if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID)) 796624322f1SOlga Kornievskaia goto out_free; 797624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 798624322f1SOlga Kornievskaia list_add(&cps->cp_list, &p_stid->sc_cp_list); 799624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 800624322f1SOlga Kornievskaia return cps; 801624322f1SOlga Kornievskaia out_free: 802624322f1SOlga Kornievskaia kfree(cps); 803624322f1SOlga Kornievskaia return NULL; 804624322f1SOlga Kornievskaia } 805624322f1SOlga Kornievskaia 806624322f1SOlga Kornievskaia void nfs4_free_copy_state(struct nfsd4_copy *copy) 807e0639dc5SOlga Kornievskaia { 808e0639dc5SOlga Kornievskaia struct nfsd_net *nn; 809e0639dc5SOlga Kornievskaia 810624322f1SOlga Kornievskaia WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID); 811e0639dc5SOlga Kornievskaia nn = net_generic(copy->cp_clp->net, nfsd_net_id); 812e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 813624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 814624322f1SOlga Kornievskaia copy->cp_stateid.stid.si_opaque.so_id); 815624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 816624322f1SOlga Kornievskaia } 817624322f1SOlga Kornievskaia 818624322f1SOlga Kornievskaia static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid) 819624322f1SOlga Kornievskaia { 820624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 821624322f1SOlga Kornievskaia struct nfsd_net *nn; 822624322f1SOlga Kornievskaia 823624322f1SOlga Kornievskaia nn = net_generic(net, nfsd_net_id); 824624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 825624322f1SOlga Kornievskaia while (!list_empty(&stid->sc_cp_list)) { 826624322f1SOlga Kornievskaia cps = list_first_entry(&stid->sc_cp_list, 827624322f1SOlga Kornievskaia struct nfs4_cpntf_state, cp_list); 828624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 829624322f1SOlga Kornievskaia } 830e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 831e0639dc5SOlga Kornievskaia } 832e0639dc5SOlga Kornievskaia 833b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 8344cdc951bSJ. Bruce Fields { 8356011695dSTrond Myklebust struct nfs4_stid *stid; 8366011695dSTrond Myklebust 837d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 8386011695dSTrond Myklebust if (!stid) 8396011695dSTrond Myklebust return NULL; 8406011695dSTrond Myklebust 841d19fb70dSKinglong Mee return openlockstateid(stid); 8426011695dSTrond Myklebust } 8436011695dSTrond Myklebust 8446011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 8456011695dSTrond Myklebust { 8466011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 8476011695dSTrond Myklebust atomic_long_dec(&num_delegations); 8484cdc951bSJ. Bruce Fields } 8494cdc951bSJ. Bruce Fields 8506282cd56SNeilBrown /* 8516282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 8526282cd56SNeilBrown * out again straight away. 8536282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 8546282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 8556282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 8566282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 8576282cd56SNeilBrown * filter. 8586282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 8596282cd56SNeilBrown * unless both are empty of course. 8606282cd56SNeilBrown * 8616282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 8626282cd56SNeilBrown * low 3 bytes as hash-table indices. 8636282cd56SNeilBrown * 864f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 8656282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 8666282cd56SNeilBrown * except when swapping the two filters. 8676282cd56SNeilBrown */ 868f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 8696282cd56SNeilBrown static struct bloom_pair { 8706282cd56SNeilBrown int entries, old_entries; 871b3f255efSArnd Bergmann time64_t swap_time; 8726282cd56SNeilBrown int new; /* index into 'set' */ 8736282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 8746282cd56SNeilBrown } blocked_delegations; 8756282cd56SNeilBrown 8766282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 8776282cd56SNeilBrown { 8786282cd56SNeilBrown u32 hash; 8796282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 8806282cd56SNeilBrown 8816282cd56SNeilBrown if (bd->entries == 0) 8826282cd56SNeilBrown return 0; 883b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 884f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 885b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 8866282cd56SNeilBrown bd->entries -= bd->old_entries; 8876282cd56SNeilBrown bd->old_entries = bd->entries; 8886282cd56SNeilBrown memset(bd->set[bd->new], 0, 8896282cd56SNeilBrown sizeof(bd->set[0])); 8906282cd56SNeilBrown bd->new = 1-bd->new; 891b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 8926282cd56SNeilBrown } 893f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 8946282cd56SNeilBrown } 89587545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 8966282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 8976282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 8986282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 8996282cd56SNeilBrown return 1; 9006282cd56SNeilBrown 9016282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 9026282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 9036282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 9046282cd56SNeilBrown return 1; 9056282cd56SNeilBrown 9066282cd56SNeilBrown return 0; 9076282cd56SNeilBrown } 9086282cd56SNeilBrown 9096282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 9106282cd56SNeilBrown { 9116282cd56SNeilBrown u32 hash; 9126282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 9136282cd56SNeilBrown 91487545899SDaniel Borkmann hash = jhash(&fh->fh_base, fh->fh_size, 0); 9156282cd56SNeilBrown 916f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 9176282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 9186282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 9196282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 9206282cd56SNeilBrown if (bd->entries == 0) 921b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 9226282cd56SNeilBrown bd->entries += 1; 923f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 9246282cd56SNeilBrown } 9256282cd56SNeilBrown 9261da177e4SLinus Torvalds static struct nfs4_delegation * 92786d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 92886d29b10SJ. Bruce Fields struct svc_fh *current_fh, 9298287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 9301da177e4SLinus Torvalds { 9311da177e4SLinus Torvalds struct nfs4_delegation *dp; 93202a3508dSTrond Myklebust long n; 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 93502a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 93602a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 93702a3508dSTrond Myklebust goto out_dec; 9386282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 93902a3508dSTrond Myklebust goto out_dec; 940d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 9415b2d21c1SNeilBrown if (dp == NULL) 94202a3508dSTrond Myklebust goto out_dec; 9436011695dSTrond Myklebust 9442a74aba7SJ. Bruce Fields /* 9452a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 9466136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 9476136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 9482a74aba7SJ. Bruce Fields */ 9492a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 950ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 951ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 9521da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 9538287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 9548287f009SSachin Bhamare get_clnt_odstate(odstate); 95599c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 956f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 957f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 9580162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 95986d29b10SJ. Bruce Fields get_nfs4_file(fp); 96086d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 9611da177e4SLinus Torvalds return dp; 96202a3508dSTrond Myklebust out_dec: 96302a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 96402a3508dSTrond Myklebust return NULL; 9651da177e4SLinus Torvalds } 9661da177e4SLinus Torvalds 9671da177e4SLinus Torvalds void 9686011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 9691da177e4SLinus Torvalds { 97011b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 9716011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 9726011695dSTrond Myklebust 9734770d722SJeff Layton might_lock(&clp->cl_lock); 9744770d722SJeff Layton 975a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 976b401be22SJeff Layton wake_up_all(&close_wq); 9776011695dSTrond Myklebust return; 978b401be22SJeff Layton } 9796011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 980624322f1SOlga Kornievskaia nfs4_free_cpntf_statelist(clp->net, s); 9814770d722SJeff Layton spin_unlock(&clp->cl_lock); 9826011695dSTrond Myklebust s->sc_free(s); 98311b9164aSTrond Myklebust if (fp) 98411b9164aSTrond Myklebust put_nfs4_file(fp); 9851da177e4SLinus Torvalds } 9861da177e4SLinus Torvalds 9879767feb2SJeff Layton void 9889767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 9899767feb2SJeff Layton { 9909767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 9919767feb2SJeff Layton 9929767feb2SJeff Layton spin_lock(&stid->sc_lock); 9939767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 9949767feb2SJeff Layton src->si_generation = 1; 9959767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 9969767feb2SJeff Layton spin_unlock(&stid->sc_lock); 9979767feb2SJeff Layton } 9989767feb2SJeff Layton 999353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 10001da177e4SLinus Torvalds { 1001eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 1002353601e7SJ. Bruce Fields 1003353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 1004353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 1005eb82dd39SJeff Layton swap(nf, fp->fi_deleg_file); 1006353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 1007353601e7SJ. Bruce Fields 1008eb82dd39SJeff Layton if (nf) 1009eb82dd39SJeff Layton nfsd_file_put(nf); 1010353601e7SJ. Bruce Fields } 1011353601e7SJ. Bruce Fields 1012353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 1013353601e7SJ. Bruce Fields { 1014cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 1015eb82dd39SJeff Layton struct nfsd_file *nf = fp->fi_deleg_file; 1016417c6629SJeff Layton 1017b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 1018b8232d33SJ. Bruce Fields 1019eb82dd39SJeff Layton vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); 1020353601e7SJ. Bruce Fields put_deleg_file(fp); 10211da177e4SLinus Torvalds } 10221da177e4SLinus Torvalds 10230af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 10240af6e690SJ. Bruce Fields { 10250af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 1026353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 10270af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 10280af6e690SJ. Bruce Fields } 10290af6e690SJ. Bruce Fields 1030cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 10316136d2b4SJ. Bruce Fields { 10323abdb607SJ. Bruce Fields s->sc_type = 0; 10336136d2b4SJ. Bruce Fields } 10346136d2b4SJ. Bruce Fields 103534ed9872SAndrew Elble /** 103668b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 103734ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 103834ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 103934ed9872SAndrew Elble * 104034ed9872SAndrew Elble * Return: 104168b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 104234ed9872SAndrew Elble */ 104334ed9872SAndrew Elble 104468b18f52SJ. Bruce Fields static bool 104568b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 1046931ee56cSBenny Halevy { 104734ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 104834ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 104934ed9872SAndrew Elble 1050cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 1051417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 1052931ee56cSBenny Halevy 105334ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 105434ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 105534ed9872SAndrew Elble if (clp == searchclp) { 105651d87bc2SFengguang Wu return true; 105734ed9872SAndrew Elble } 105834ed9872SAndrew Elble } 105951d87bc2SFengguang Wu return false; 106034ed9872SAndrew Elble } 106134ed9872SAndrew Elble 106234ed9872SAndrew Elble /** 106334ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 106434ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 106534ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 106634ed9872SAndrew Elble * 106734ed9872SAndrew Elble * Return: 106834ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 106934ed9872SAndrew Elble * 107034ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 107134ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 107234ed9872SAndrew Elble * 107334ed9872SAndrew Elble */ 107434ed9872SAndrew Elble 107534ed9872SAndrew Elble static int 107634ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 107734ed9872SAndrew Elble { 107834ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 107934ed9872SAndrew Elble 108034ed9872SAndrew Elble lockdep_assert_held(&state_lock); 108134ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 108234ed9872SAndrew Elble 108368b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 108468b18f52SJ. Bruce Fields return -EAGAIN; 1085a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 10863fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 1087931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 108834ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 108934ed9872SAndrew Elble return 0; 1090931ee56cSBenny Halevy } 1091931ee56cSBenny Halevy 10923fcbbd24SJeff Layton static bool 109342690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 10941da177e4SLinus Torvalds { 109511b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 109602e1215fSJeff Layton 109742690676SJeff Layton lockdep_assert_held(&state_lock); 109842690676SJeff Layton 10993fcbbd24SJeff Layton if (list_empty(&dp->dl_perfile)) 11003fcbbd24SJeff Layton return false; 11013fcbbd24SJeff Layton 1102b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 1103d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 1104d55a166cSJeff Layton ++dp->dl_time; 1105417c6629SJeff Layton spin_lock(&fp->fi_lock); 1106931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 11071da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 110802e1215fSJeff Layton list_del_init(&dp->dl_perfile); 110902e1215fSJeff Layton spin_unlock(&fp->fi_lock); 11103fcbbd24SJeff Layton return true; 1111cbf7a75bSJ. Bruce Fields } 11123bd64a5bSJ. Bruce Fields 11133bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 11143bd64a5bSJ. Bruce Fields { 11153fcbbd24SJeff Layton bool unhashed; 11163fcbbd24SJeff Layton 111742690676SJeff Layton spin_lock(&state_lock); 11183fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 111942690676SJeff Layton spin_unlock(&state_lock); 11200af6e690SJ. Bruce Fields if (unhashed) 11210af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 11223fcbbd24SJeff Layton } 11233bd64a5bSJ. Bruce Fields 11243bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 11253bd64a5bSJ. Bruce Fields { 11263bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 11273bd64a5bSJ. Bruce Fields 11282d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 11292d4a532dSJeff Layton 11300af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 11313bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 11320af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 11332d4a532dSJeff Layton spin_lock(&clp->cl_lock); 11342d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 11352d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 11363bd64a5bSJ. Bruce Fields } 11370af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 11383bd64a5bSJ. Bruce Fields } 11393bd64a5bSJ. Bruce Fields 11401da177e4SLinus Torvalds /* 11411da177e4SLinus Torvalds * SETCLIENTID state 11421da177e4SLinus Torvalds */ 11431da177e4SLinus Torvalds 1144ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1145ddc04c41SJ. Bruce Fields { 1146ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1147ddc04c41SJ. Bruce Fields } 1148ddc04c41SJ. Bruce Fields 11496b189105SScott Mayhew static unsigned int clientstr_hashval(struct xdr_netobj name) 1150ddc04c41SJ. Bruce Fields { 11516b189105SScott Mayhew return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; 1152ddc04c41SJ. Bruce Fields } 1153ddc04c41SJ. Bruce Fields 11541da177e4SLinus Torvalds /* 1155f9d7562fSJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 1156f9d7562fSJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 1157f9d7562fSJ. Bruce Fields * only what share bits are currently in force, but also what 1158f9d7562fSJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 1159f9d7562fSJ. Bruce Fields * to enforce the recommendation of rfc 3530 14.2.19 that the server 1160f9d7562fSJ. Bruce Fields * return an error if the client attempt to downgrade to a combination 1161f9d7562fSJ. Bruce Fields * of share bits not explicable by closing some of its previous opens. 1162f9d7562fSJ. Bruce Fields * 1163f9d7562fSJ. Bruce Fields * XXX: This enforcement is actually incomplete, since we don't keep 1164f9d7562fSJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 1165f9d7562fSJ. Bruce Fields * 1166f9d7562fSJ. Bruce Fields * OPEN allow read, deny write 1167f9d7562fSJ. Bruce Fields * OPEN allow both, deny none 1168f9d7562fSJ. Bruce Fields * DOWNGRADE allow read, deny none 1169f9d7562fSJ. Bruce Fields * 1170f9d7562fSJ. Bruce Fields * which we should reject. 1171f9d7562fSJ. Bruce Fields */ 11725ae037e5SJeff Layton static unsigned int 11735ae037e5SJeff Layton bmap_to_share_mode(unsigned long bmap) { 1174f9d7562fSJ. Bruce Fields int i; 11755ae037e5SJeff Layton unsigned int access = 0; 1176f9d7562fSJ. Bruce Fields 1177f9d7562fSJ. Bruce Fields for (i = 1; i < 4; i++) { 1178f9d7562fSJ. Bruce Fields if (test_bit(i, &bmap)) 11795ae037e5SJeff Layton access |= i; 1180f9d7562fSJ. Bruce Fields } 11815ae037e5SJeff Layton return access; 1182f9d7562fSJ. Bruce Fields } 1183f9d7562fSJ. Bruce Fields 118482c5ff1bSJeff Layton /* set share access for a given stateid */ 118582c5ff1bSJeff Layton static inline void 118682c5ff1bSJeff Layton set_access(u32 access, struct nfs4_ol_stateid *stp) 118782c5ff1bSJeff Layton { 1188c11c591fSJeff Layton unsigned char mask = 1 << access; 1189c11c591fSJeff Layton 1190c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1191c11c591fSJeff Layton stp->st_access_bmap |= mask; 119282c5ff1bSJeff Layton } 119382c5ff1bSJeff Layton 119482c5ff1bSJeff Layton /* clear share access for a given stateid */ 119582c5ff1bSJeff Layton static inline void 119682c5ff1bSJeff Layton clear_access(u32 access, struct nfs4_ol_stateid *stp) 119782c5ff1bSJeff Layton { 1198c11c591fSJeff Layton unsigned char mask = 1 << access; 1199c11c591fSJeff Layton 1200c11c591fSJeff Layton WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 1201c11c591fSJeff Layton stp->st_access_bmap &= ~mask; 120282c5ff1bSJeff Layton } 120382c5ff1bSJeff Layton 120482c5ff1bSJeff Layton /* test whether a given stateid has access */ 120582c5ff1bSJeff Layton static inline bool 120682c5ff1bSJeff Layton test_access(u32 access, struct nfs4_ol_stateid *stp) 120782c5ff1bSJeff Layton { 1208c11c591fSJeff Layton unsigned char mask = 1 << access; 1209c11c591fSJeff Layton 1210c11c591fSJeff Layton return (bool)(stp->st_access_bmap & mask); 121182c5ff1bSJeff Layton } 121282c5ff1bSJeff Layton 1213ce0fc43cSJeff Layton /* set share deny for a given stateid */ 1214ce0fc43cSJeff Layton static inline void 1215c11c591fSJeff Layton set_deny(u32 deny, struct nfs4_ol_stateid *stp) 1216ce0fc43cSJeff Layton { 1217c11c591fSJeff Layton unsigned char mask = 1 << deny; 1218c11c591fSJeff Layton 1219c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1220c11c591fSJeff Layton stp->st_deny_bmap |= mask; 1221ce0fc43cSJeff Layton } 1222ce0fc43cSJeff Layton 1223ce0fc43cSJeff Layton /* clear share deny for a given stateid */ 1224ce0fc43cSJeff Layton static inline void 1225c11c591fSJeff Layton clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 1226ce0fc43cSJeff Layton { 1227c11c591fSJeff Layton unsigned char mask = 1 << deny; 1228c11c591fSJeff Layton 1229c11c591fSJeff Layton WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 1230c11c591fSJeff Layton stp->st_deny_bmap &= ~mask; 1231ce0fc43cSJeff Layton } 1232ce0fc43cSJeff Layton 1233ce0fc43cSJeff Layton /* test whether a given stateid is denying specific access */ 1234ce0fc43cSJeff Layton static inline bool 1235c11c591fSJeff Layton test_deny(u32 deny, struct nfs4_ol_stateid *stp) 1236ce0fc43cSJeff Layton { 1237c11c591fSJeff Layton unsigned char mask = 1 << deny; 1238c11c591fSJeff Layton 1239c11c591fSJeff Layton return (bool)(stp->st_deny_bmap & mask); 1240f9d7562fSJ. Bruce Fields } 1241f9d7562fSJ. Bruce Fields 1242f9d7562fSJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 1243f9d7562fSJ. Bruce Fields { 12448f34a430SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 1245f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 1246f9d7562fSJ. Bruce Fields return O_RDONLY; 1247f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 1248f9d7562fSJ. Bruce Fields return O_WRONLY; 1249f9d7562fSJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 1250f9d7562fSJ. Bruce Fields return O_RDWR; 1251f9d7562fSJ. Bruce Fields } 1252063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 1253063b0fb9SJ. Bruce Fields return O_RDONLY; 1254f9d7562fSJ. Bruce Fields } 1255f9d7562fSJ. Bruce Fields 1256baeb4ff0SJeff Layton /* 1257baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1258baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1259baeb4ff0SJeff Layton */ 1260baeb4ff0SJeff Layton static void 1261baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1262baeb4ff0SJeff Layton { 1263baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1264baeb4ff0SJeff Layton 1265baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1266baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1267baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1268baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1269baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1270baeb4ff0SJeff Layton } 1271baeb4ff0SJeff Layton 1272baeb4ff0SJeff Layton static void 1273baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1274baeb4ff0SJeff Layton { 1275baeb4ff0SJeff Layton int i; 1276baeb4ff0SJeff Layton bool change = false; 1277baeb4ff0SJeff Layton 1278baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1279baeb4ff0SJeff Layton if ((i & deny) != i) { 1280baeb4ff0SJeff Layton change = true; 1281baeb4ff0SJeff Layton clear_deny(i, stp); 1282baeb4ff0SJeff Layton } 1283baeb4ff0SJeff Layton } 1284baeb4ff0SJeff Layton 1285baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1286baeb4ff0SJeff Layton if (change) 128711b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1288baeb4ff0SJeff Layton } 1289baeb4ff0SJeff Layton 129082c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 129182c5ff1bSJeff Layton static void 129282c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 129382c5ff1bSJeff Layton { 129482c5ff1bSJeff Layton int i; 129511b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1296baeb4ff0SJeff Layton 1297baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1298baeb4ff0SJeff Layton recalculate_deny_mode(fp); 129982c5ff1bSJeff Layton 130082c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 130182c5ff1bSJeff Layton if (test_access(i, stp)) 130211b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 130382c5ff1bSJeff Layton clear_access(i, stp); 130482c5ff1bSJeff Layton } 130582c5ff1bSJeff Layton } 130682c5ff1bSJeff Layton 1307d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1308d50ffdedSKinglong Mee { 1309d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1310d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1311d50ffdedSKinglong Mee } 1312d50ffdedSKinglong Mee 13136b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 13146b180f0bSJeff Layton { 1315a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1316a819ecc1SJeff Layton 1317a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1318a819ecc1SJeff Layton 1319a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 13206b180f0bSJeff Layton return; 13218f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1322a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1323d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 13246b180f0bSJeff Layton } 13256b180f0bSJeff Layton 1326a451b123STrond Myklebust static bool 1327a451b123STrond Myklebust nfs4_ol_stateid_unhashed(const struct nfs4_ol_stateid *stp) 1328a451b123STrond Myklebust { 1329a451b123STrond Myklebust return list_empty(&stp->st_perfile); 1330a451b123STrond Myklebust } 1331a451b123STrond Myklebust 1332e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1333529d7b2aSJ. Bruce Fields { 133411b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 13351d31a253STrond Myklebust 13361c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 13371c755dc1SJeff Layton 1338e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1339e8568739SJeff Layton return false; 1340e8568739SJeff Layton 13411d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1342e8568739SJeff Layton list_del_init(&stp->st_perfile); 13431d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1344529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1345e8568739SJeff Layton return true; 1346529d7b2aSJ. Bruce Fields } 1347529d7b2aSJ. Bruce Fields 13486011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1349529d7b2aSJ. Bruce Fields { 13506011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 13514665e2baSJ. Bruce Fields 13528287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 13536011695dSTrond Myklebust release_all_access(stp); 1354d3134b10SJeff Layton if (stp->st_stateowner) 1355d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 13566011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1357529d7b2aSJ. Bruce Fields } 1358529d7b2aSJ. Bruce Fields 1359b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1360529d7b2aSJ. Bruce Fields { 1361b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1362b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1363eb82dd39SJeff Layton struct nfsd_file *nf; 1364529d7b2aSJ. Bruce Fields 1365eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 1366eb82dd39SJeff Layton if (nf) { 1367eb82dd39SJeff Layton get_file(nf->nf_file); 1368eb82dd39SJeff Layton filp_close(nf->nf_file, (fl_owner_t)lo); 1369eb82dd39SJeff Layton nfsd_file_put(nf); 1370eb82dd39SJeff Layton } 1371b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1372b49e084dSJeff Layton } 1373b49e084dSJeff Layton 13742c41beb0SJeff Layton /* 13752c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 13762c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 13772c41beb0SJeff Layton * reaplist for later destruction. 13782c41beb0SJeff Layton */ 13792c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 13802c41beb0SJeff Layton struct list_head *reaplist) 13812c41beb0SJeff Layton { 13822c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 13832c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 13842c41beb0SJeff Layton 13852c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 13862c41beb0SJeff Layton 13872c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 13882c41beb0SJeff Layton 1389a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 13902c41beb0SJeff Layton wake_up_all(&close_wq); 13912c41beb0SJeff Layton return; 13922c41beb0SJeff Layton } 13932c41beb0SJeff Layton 13942c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 13952c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 13962c41beb0SJeff Layton } 13972c41beb0SJeff Layton 1398e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 13993c1c995cSJeff Layton { 1400f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 14013c1c995cSJeff Layton 1402a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1403a451b123STrond Myklebust return false; 14043c1c995cSJeff Layton list_del_init(&stp->st_locks); 1405cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1406a451b123STrond Myklebust return true; 14073c1c995cSJeff Layton } 14083c1c995cSJeff Layton 14095adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1410b49e084dSJeff Layton { 1411f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1412e8568739SJeff Layton bool unhashed; 14131c755dc1SJeff Layton 1414f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1415e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1416f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1417e8568739SJeff Layton if (unhashed) 14186011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1419529d7b2aSJ. Bruce Fields } 1420529d7b2aSJ. Bruce Fields 1421c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1422529d7b2aSJ. Bruce Fields { 1423d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1424c58c6610STrond Myklebust 1425d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1426c58c6610STrond Myklebust 14278f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 14288f4b54c5SJeff Layton } 14298f4b54c5SJeff Layton 14302c41beb0SJeff Layton /* 14312c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 14322c41beb0SJeff Layton * fully unhashed. 14332c41beb0SJeff Layton */ 14342c41beb0SJeff Layton static void 14352c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 14362c41beb0SJeff Layton { 14372c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1438fb94d766SKinglong Mee struct nfs4_file *fp; 14392c41beb0SJeff Layton 14402c41beb0SJeff Layton might_sleep(); 14412c41beb0SJeff Layton 14422c41beb0SJeff Layton while (!list_empty(reaplist)) { 14432c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 14442c41beb0SJeff Layton st_locks); 14452c41beb0SJeff Layton list_del(&stp->st_locks); 1446fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 14472c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1448fb94d766SKinglong Mee if (fp) 1449fb94d766SKinglong Mee put_nfs4_file(fp); 14502c41beb0SJeff Layton } 14512c41beb0SJeff Layton } 14522c41beb0SJeff Layton 1453d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1454d83017f9SJeff Layton struct list_head *reaplist) 14553c87b9b7STrond Myklebust { 14563c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 14573c87b9b7STrond Myklebust 1458e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1459e8568739SJeff Layton 14603c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 14613c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 14623c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1463e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1464d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1465529d7b2aSJ. Bruce Fields } 1466529d7b2aSJ. Bruce Fields } 1467529d7b2aSJ. Bruce Fields 1468e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1469d83017f9SJeff Layton struct list_head *reaplist) 14702283963fSJ. Bruce Fields { 14712c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 14722c41beb0SJeff Layton 1473a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1474a451b123STrond Myklebust return false; 1475d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1476a451b123STrond Myklebust return true; 147738c387b5SJ. Bruce Fields } 147838c387b5SJ. Bruce Fields 147938c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 148038c387b5SJ. Bruce Fields { 14812c41beb0SJeff Layton LIST_HEAD(reaplist); 14822c41beb0SJeff Layton 14832c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1484e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 14852c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 14862c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 14872c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 14882283963fSJ. Bruce Fields } 14892283963fSJ. Bruce Fields 14907ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1491f1d110caSJ. Bruce Fields { 1492d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 14937ffb5880STrond Myklebust 1494d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 14957ffb5880STrond Myklebust 14968f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 14978f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1498f1d110caSJ. Bruce Fields } 1499f1d110caSJ. Bruce Fields 1500f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1501f7a4d872SJ. Bruce Fields { 1502217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1503217526e7SJeff Layton nfsd_net_id); 1504217526e7SJeff Layton struct nfs4_ol_stateid *s; 1505f7a4d872SJ. Bruce Fields 1506217526e7SJeff Layton spin_lock(&nn->client_lock); 1507217526e7SJeff Layton s = oo->oo_last_closed_stid; 1508f7a4d872SJ. Bruce Fields if (s) { 1509d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1510f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1511f7a4d872SJ. Bruce Fields } 1512217526e7SJeff Layton spin_unlock(&nn->client_lock); 1513217526e7SJeff Layton if (s) 1514217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1515f7a4d872SJ. Bruce Fields } 1516f7a4d872SJ. Bruce Fields 15172c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 15188f4b54c5SJeff Layton { 15198f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1520d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 15212c41beb0SJeff Layton struct list_head reaplist; 15227ffb5880STrond Myklebust 15232c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 15247ffb5880STrond Myklebust 1525d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 15267ffb5880STrond Myklebust unhash_openowner_locked(oo); 15272c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 15282c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 15292c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1530e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 15312c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 15322c41beb0SJeff Layton } 1533d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 15342c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1535f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 15366b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1537f1d110caSJ. Bruce Fields } 1538f1d110caSJ. Bruce Fields 15395282fd72SMarc Eshel static inline int 15405282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 15415282fd72SMarc Eshel { 15425282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 15435282fd72SMarc Eshel 15445282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 15455282fd72SMarc Eshel } 15465282fd72SMarc Eshel 1547135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 15485282fd72SMarc Eshel static inline void 15495282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 15505282fd72SMarc Eshel { 15515282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 15525282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 15535282fd72SMarc Eshel } 15548f199b82STrond Myklebust #else 15558f199b82STrond Myklebust static inline void 15568f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 15578f199b82STrond Myklebust { 15588f199b82STrond Myklebust } 15598f199b82STrond Myklebust #endif 15608f199b82STrond Myklebust 15619411b1d4SJ. Bruce Fields /* 15629411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 15639411b1d4SJ. Bruce Fields * won't be used for replay. 15649411b1d4SJ. Bruce Fields */ 15659411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 15669411b1d4SJ. Bruce Fields { 15679411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 15689411b1d4SJ. Bruce Fields 15699411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 15709411b1d4SJ. Bruce Fields return; 15719411b1d4SJ. Bruce Fields 15729411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 157358fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 15749411b1d4SJ. Bruce Fields return; 15759411b1d4SJ. Bruce Fields } 15769411b1d4SJ. Bruce Fields if (!so) 15779411b1d4SJ. Bruce Fields return; 15789411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 15799411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 15809411b1d4SJ. Bruce Fields so->so_seqid++; 15819411b1d4SJ. Bruce Fields return; 15829411b1d4SJ. Bruce Fields } 15835282fd72SMarc Eshel 1584ec6b5d7bSAndy Adamson static void 1585ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1586ec6b5d7bSAndy Adamson { 1587ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1588ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1589ec6b5d7bSAndy Adamson 1590ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1591ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1592ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1593ec6b5d7bSAndy Adamson sid->reserved = 0; 1594ec6b5d7bSAndy Adamson } 1595ec6b5d7bSAndy Adamson 1596ec6b5d7bSAndy Adamson /* 1597a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1598a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1599a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1600a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1601a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1602a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1603a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1604a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1605a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1606a649637cSAndy Adamson * for the SEQUENCE op response: 1607ec6b5d7bSAndy Adamson */ 1608a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1609a649637cSAndy Adamson 1610557ce264SAndy Adamson static void 1611557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1612557ce264SAndy Adamson { 1613557ce264SAndy Adamson int i; 1614557ce264SAndy Adamson 161553da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 161653da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1617557ce264SAndy Adamson kfree(ses->se_slots[i]); 1618557ce264SAndy Adamson } 161953da6a53SJ. Bruce Fields } 1620557ce264SAndy Adamson 1621efe0cb6dSJ. Bruce Fields /* 1622efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1623efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1624efe0cb6dSJ. Bruce Fields */ 162555c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1626efe0cb6dSJ. Bruce Fields { 162755c760cfSJ. Bruce Fields u32 size; 1628efe0cb6dSJ. Bruce Fields 162955c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 163055c760cfSJ. Bruce Fields size = 0; 163155c760cfSJ. Bruce Fields else 163255c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 163355c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1634557ce264SAndy Adamson } 1635557ce264SAndy Adamson 16365b6feee9SJ. Bruce Fields /* 16375b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 16385b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 163942b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 16405b6feee9SJ. Bruce Fields */ 16412030ca56SNeilBrown static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 16425b6feee9SJ. Bruce Fields { 164355c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 164455c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 1645c54f24e3SJ. Bruce Fields unsigned long avail, total_avail; 16462030ca56SNeilBrown unsigned int scale_factor; 16475b6feee9SJ. Bruce Fields 16485b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 16497f49fd5dSNeilBrown if (nfsd_drc_max_mem > nfsd_drc_mem_used) 1650c54f24e3SJ. Bruce Fields total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 16517f49fd5dSNeilBrown else 16527f49fd5dSNeilBrown /* We have handed out more space than we chose in 16537f49fd5dSNeilBrown * set_max_drc() to allow. That isn't really a 16547f49fd5dSNeilBrown * problem as long as that doesn't make us think we 16557f49fd5dSNeilBrown * have lots more due to integer overflow. 16567f49fd5dSNeilBrown */ 16577f49fd5dSNeilBrown total_avail = 0; 1658c54f24e3SJ. Bruce Fields avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1659de766e57SJ. Bruce Fields /* 16602030ca56SNeilBrown * Never use more than a fraction of the remaining memory, 16617f49fd5dSNeilBrown * unless it's the only way to give this client a slot. 16622030ca56SNeilBrown * The chosen fraction is either 1/8 or 1/number of threads, 16632030ca56SNeilBrown * whichever is smaller. This ensures there are adequate 16642030ca56SNeilBrown * slots to support multiple clients per thread. 16657f49fd5dSNeilBrown * Give the client one slot even if that would require 16667f49fd5dSNeilBrown * over-allocation--it is better than failure. 1667de766e57SJ. Bruce Fields */ 16682030ca56SNeilBrown scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); 16692030ca56SNeilBrown 16702030ca56SNeilBrown avail = clamp_t(unsigned long, avail, slotsize, 16712030ca56SNeilBrown total_avail/scale_factor); 16725b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 16737f49fd5dSNeilBrown num = max_t(int, num, 1); 16745b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 16755b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 16765b6feee9SJ. Bruce Fields 16775b6feee9SJ. Bruce Fields return num; 16785b6feee9SJ. Bruce Fields } 16795b6feee9SJ. Bruce Fields 168055c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 16815b6feee9SJ. Bruce Fields { 168255c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 168355c760cfSJ. Bruce Fields 16845b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 168555c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 16865b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 16875b6feee9SJ. Bruce Fields } 16885b6feee9SJ. Bruce Fields 168960810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 169060810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 16915b6feee9SJ. Bruce Fields { 169260810e54SKinglong Mee int numslots = fattrs->maxreqs; 169360810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 16945b6feee9SJ. Bruce Fields struct nfsd4_session *new; 16955b6feee9SJ. Bruce Fields int mem, i; 1696ec6b5d7bSAndy Adamson 1697c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1698ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 16995b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1700ec6b5d7bSAndy Adamson 17015b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 17026c18ba9fSAlexandros Batsakis if (!new) 17035b6feee9SJ. Bruce Fields return NULL; 1704ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 17055b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 170655c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 17075b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1708ec6b5d7bSAndy Adamson goto out_free; 1709ec6b5d7bSAndy Adamson } 171060810e54SKinglong Mee 171160810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 171260810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 171360810e54SKinglong Mee 17145b6feee9SJ. Bruce Fields return new; 17155b6feee9SJ. Bruce Fields out_free: 17165b6feee9SJ. Bruce Fields while (i--) 17175b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 17185b6feee9SJ. Bruce Fields kfree(new); 17195b6feee9SJ. Bruce Fields return NULL; 17205b6feee9SJ. Bruce Fields } 17215b6feee9SJ. Bruce Fields 172219cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 172319cf5c02SJ. Bruce Fields { 172419cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 172519cf5c02SJ. Bruce Fields kfree(c); 172619cf5c02SJ. Bruce Fields } 172719cf5c02SJ. Bruce Fields 172819cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 172919cf5c02SJ. Bruce Fields { 173019cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 173119cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 173219cf5c02SJ. Bruce Fields 173319cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 173419cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 173519cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 173619cf5c02SJ. Bruce Fields free_conn(c); 173719cf5c02SJ. Bruce Fields } 1738eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 17392e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 174019cf5c02SJ. Bruce Fields } 174119cf5c02SJ. Bruce Fields 1742d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1743c7662518SJ. Bruce Fields { 1744c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1745c7662518SJ. Bruce Fields 1746c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1747c7662518SJ. Bruce Fields if (!conn) 1748db90681dSJ. Bruce Fields return NULL; 1749c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1750c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1751d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1752db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1753db90681dSJ. Bruce Fields return conn; 1754db90681dSJ. Bruce Fields } 1755db90681dSJ. Bruce Fields 1756328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1757328ead28SJ. Bruce Fields { 1758328ead28SJ. Bruce Fields conn->cn_session = ses; 1759328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1760328ead28SJ. Bruce Fields } 1761328ead28SJ. Bruce Fields 1762db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1763db90681dSJ. Bruce Fields { 1764db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1765c7662518SJ. Bruce Fields 1766c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1767328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1768c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1769db90681dSJ. Bruce Fields } 1770c7662518SJ. Bruce Fields 177121b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1772db90681dSJ. Bruce Fields { 177319cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 177421b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1775db90681dSJ. Bruce Fields } 1776db90681dSJ. Bruce Fields 1777e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1778db90681dSJ. Bruce Fields { 177921b75b01SJ. Bruce Fields int ret; 1780db90681dSJ. Bruce Fields 1781db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 178221b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 178321b75b01SJ. Bruce Fields if (ret) 178421b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 178521b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 178657a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 178757a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1788c7662518SJ. Bruce Fields } 1789c7662518SJ. Bruce Fields 1790e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 17911d1bc8f2SJ. Bruce Fields { 17921d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 17931d1bc8f2SJ. Bruce Fields 1794e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 17951d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1796e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 17971d1bc8f2SJ. Bruce Fields } 17981d1bc8f2SJ. Bruce Fields 17991d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 180019cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1801c7662518SJ. Bruce Fields { 180219cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 180319cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 180419cf5c02SJ. Bruce Fields 180519cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 180619cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 180719cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 180819cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 180919cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 181019cf5c02SJ. Bruce Fields 181119cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 181219cf5c02SJ. Bruce Fields free_conn(c); 181319cf5c02SJ. Bruce Fields 181419cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 181519cf5c02SJ. Bruce Fields } 181619cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1817c7662518SJ. Bruce Fields } 1818c7662518SJ. Bruce Fields 18191377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 18201377b69eSJ. Bruce Fields { 18211377b69eSJ. Bruce Fields free_session_slots(ses); 18221377b69eSJ. Bruce Fields kfree(ses); 18231377b69eSJ. Bruce Fields } 18241377b69eSJ. Bruce Fields 182566b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1826508dc6e1SBenny Halevy { 1827c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 182855c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1829c7662518SJ. Bruce Fields __free_session(ses); 1830a827bcb2SJ. Bruce Fields } 1831ec6b5d7bSAndy Adamson 1832135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1833a827bcb2SJ. Bruce Fields { 1834a827bcb2SJ. Bruce Fields int idx; 18351872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1836a827bcb2SJ. Bruce Fields 1837ec6b5d7bSAndy Adamson new->se_client = clp; 1838ec6b5d7bSAndy Adamson gen_sessionid(new); 1839ec6b5d7bSAndy Adamson 1840c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1841c7662518SJ. Bruce Fields 1842ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1843ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 18448b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1845c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 184666b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 18475b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 18481872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 18494c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1850ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 18514c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 185260810e54SKinglong Mee 1853b0d2e42cSChuck Lever { 1854edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1855dcbeaa68SJ. Bruce Fields /* 1856dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1857dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1858dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1859dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1860dcbeaa68SJ. Bruce Fields * future: 1861dcbeaa68SJ. Bruce Fields */ 1862edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1863edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1864edd76786SJ. Bruce Fields } 1865ec6b5d7bSAndy Adamson } 1866ec6b5d7bSAndy Adamson 18679089f1b4SBenny Halevy /* caller must hold client_lock */ 18685282fd72SMarc Eshel static struct nfsd4_session * 1869d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 18705282fd72SMarc Eshel { 18715282fd72SMarc Eshel struct nfsd4_session *elem; 18725282fd72SMarc Eshel int idx; 18731872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 18745282fd72SMarc Eshel 18750a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 18760a880a28STrond Myklebust 18775282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 18785282fd72SMarc Eshel idx = hash_sessionid(sessionid); 18795282fd72SMarc Eshel /* Search in the appropriate list */ 18801872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 18815282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 18825282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 18835282fd72SMarc Eshel return elem; 18845282fd72SMarc Eshel } 18855282fd72SMarc Eshel } 18865282fd72SMarc Eshel 18875282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 18885282fd72SMarc Eshel return NULL; 18895282fd72SMarc Eshel } 18905282fd72SMarc Eshel 1891d4e19e70STrond Myklebust static struct nfsd4_session * 1892d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1893d4e19e70STrond Myklebust __be32 *ret) 1894d4e19e70STrond Myklebust { 1895d4e19e70STrond Myklebust struct nfsd4_session *session; 1896d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1897d4e19e70STrond Myklebust 1898d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1899d4e19e70STrond Myklebust if (!session) 1900d4e19e70STrond Myklebust goto out; 1901d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1902d4e19e70STrond Myklebust if (status) 1903d4e19e70STrond Myklebust session = NULL; 1904d4e19e70STrond Myklebust out: 1905d4e19e70STrond Myklebust *ret = status; 1906d4e19e70STrond Myklebust return session; 1907d4e19e70STrond Myklebust } 1908d4e19e70STrond Myklebust 19099089f1b4SBenny Halevy /* caller must hold client_lock */ 19107116ed6bSAndy Adamson static void 19115282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 19127116ed6bSAndy Adamson { 19130a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 19140a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 19150a880a28STrond Myklebust 19160a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 19170a880a28STrond Myklebust 19187116ed6bSAndy Adamson list_del(&ses->se_hash); 19194c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 19207116ed6bSAndy Adamson list_del(&ses->se_perclnt); 19214c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 19225282fd72SMarc Eshel } 19235282fd72SMarc Eshel 19241da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 19251da177e4SLinus Torvalds static int 19262c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 19271da177e4SLinus Torvalds { 1928bbc7f33aSJ. Bruce Fields /* 1929bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 1930bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 1931bbc7f33aSJ. Bruce Fields * a safe assumption: 1932bbc7f33aSJ. Bruce Fields */ 1933bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 19341da177e4SLinus Torvalds return 0; 1935dd5e3fbcSChuck Lever trace_nfsd_clid_stale(clid); 19361da177e4SLinus Torvalds return 1; 19371da177e4SLinus Torvalds } 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds /* 19401da177e4SLinus Torvalds * XXX Should we use a slab cache ? 19411da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 19421da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 19431da177e4SLinus Torvalds */ 194435bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 19451da177e4SLinus Torvalds { 19461da177e4SLinus Torvalds struct nfs4_client *clp; 1947d4f0489fSTrond Myklebust int i; 19481da177e4SLinus Torvalds 19499258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 195035bba9a3SJ. Bruce Fields if (clp == NULL) 195135bba9a3SJ. Bruce Fields return NULL; 19526f4859b8SJ. Bruce Fields xdr_netobj_dup(&clp->cl_name, &name, GFP_KERNEL); 1953d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 1954d4f0489fSTrond Myklebust goto err_no_name; 19556da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 19566da2ec56SKees Cook sizeof(struct list_head), 19576da2ec56SKees Cook GFP_KERNEL); 1958d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 1959d4f0489fSTrond Myklebust goto err_no_hashtbl; 1960d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 1961d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 19625694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 19635694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 196414ed14ccSJ. Bruce Fields atomic_set(&clp->cl_rpc_users, 0); 19655694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 19665694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 19675694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 19685694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 19695694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 19705694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 19719cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 19729cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 19739cf514ccSChristoph Hellwig #endif 1974e0639dc5SOlga Kornievskaia INIT_LIST_HEAD(&clp->async_copies); 1975e0639dc5SOlga Kornievskaia spin_lock_init(&clp->async_lock); 19765694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 19775694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 19781da177e4SLinus Torvalds return clp; 1979d4f0489fSTrond Myklebust err_no_hashtbl: 1980d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 1981d4f0489fSTrond Myklebust err_no_name: 19829258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 1983d4f0489fSTrond Myklebust return NULL; 19841da177e4SLinus Torvalds } 19851da177e4SLinus Torvalds 198659f8e91bSJ. Bruce Fields static void __free_client(struct kref *k) 198759f8e91bSJ. Bruce Fields { 1988e8a79fb1SJ. Bruce Fields struct nfsdfs_client *c = container_of(k, struct nfsdfs_client, cl_ref); 1989e8a79fb1SJ. Bruce Fields struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs); 199059f8e91bSJ. Bruce Fields 199159f8e91bSJ. Bruce Fields free_svc_cred(&clp->cl_cred); 199259f8e91bSJ. Bruce Fields kfree(clp->cl_ownerstr_hashtbl); 199359f8e91bSJ. Bruce Fields kfree(clp->cl_name.data); 199479123444SJ. Bruce Fields kfree(clp->cl_nii_domain.data); 199579123444SJ. Bruce Fields kfree(clp->cl_nii_name.data); 199659f8e91bSJ. Bruce Fields idr_destroy(&clp->cl_stateids); 199759f8e91bSJ. Bruce Fields kmem_cache_free(client_slab, clp); 199859f8e91bSJ. Bruce Fields } 199959f8e91bSJ. Bruce Fields 2000297e57a2SYueHaibing static void drop_client(struct nfs4_client *clp) 200159f8e91bSJ. Bruce Fields { 2002e8a79fb1SJ. Bruce Fields kref_put(&clp->cl_nfsdfs.cl_ref, __free_client); 200359f8e91bSJ. Bruce Fields } 200459f8e91bSJ. Bruce Fields 20054dd86e15STrond Myklebust static void 20061da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 20071da177e4SLinus Torvalds { 2008792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 2009792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2010792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 2011792c95ddSJ. Bruce Fields se_perclnt); 2012792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 201366b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 201466b2b9b2SJ. Bruce Fields free_session(ses); 2015792c95ddSJ. Bruce Fields } 20164cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 201789c905beSJ. Bruce Fields if (clp->cl_nfsd_dentry) { 2018e8a79fb1SJ. Bruce Fields nfsd_client_rmdir(clp->cl_nfsd_dentry); 201989c905beSJ. Bruce Fields clp->cl_nfsd_dentry = NULL; 202089c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 202189c905beSJ. Bruce Fields } 202259f8e91bSJ. Bruce Fields drop_client(clp); 20231da177e4SLinus Torvalds } 20241da177e4SLinus Torvalds 202584d38ac9SBenny Halevy /* must be called under the client_lock */ 20264beb345bSTrond Myklebust static void 202784d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 202884d38ac9SBenny Halevy { 20294beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2030792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2031792c95ddSJ. Bruce Fields 20320a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20330a880a28STrond Myklebust 20344beb345bSTrond Myklebust /* Mark the client as expired! */ 20354beb345bSTrond Myklebust clp->cl_time = 0; 20364beb345bSTrond Myklebust /* Make it invisible */ 20374beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 20384beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 20394beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 20404beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 20414beb345bSTrond Myklebust else 20424beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 20434beb345bSTrond Myklebust } 20444beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 20454c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 2046792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 2047792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 20484c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 204984d38ac9SBenny Halevy } 205084d38ac9SBenny Halevy 20511da177e4SLinus Torvalds static void 20524beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 20534beb345bSTrond Myklebust { 20544beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20554beb345bSTrond Myklebust 20564beb345bSTrond Myklebust spin_lock(&nn->client_lock); 20574beb345bSTrond Myklebust unhash_client_locked(clp); 20584beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 20594beb345bSTrond Myklebust } 20604beb345bSTrond Myklebust 206197403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 206297403d95SJeff Layton { 206314ed14ccSJ. Bruce Fields if (atomic_read(&clp->cl_rpc_users)) 206497403d95SJeff Layton return nfserr_jukebox; 206597403d95SJeff Layton unhash_client_locked(clp); 206697403d95SJeff Layton return nfs_ok; 206797403d95SJeff Layton } 206897403d95SJeff Layton 20694beb345bSTrond Myklebust static void 20704beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 20711da177e4SLinus Torvalds { 207268ef3bc3SJeff Layton int i; 2073fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 20741da177e4SLinus Torvalds struct nfs4_delegation *dp; 20751da177e4SLinus Torvalds struct list_head reaplist; 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 2078cdc97505SBenny Halevy spin_lock(&state_lock); 2079ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 2080ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 20813fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 208242690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 20831da177e4SLinus Torvalds } 2084cdc97505SBenny Halevy spin_unlock(&state_lock); 20851da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 20861da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 208742690676SJeff Layton list_del_init(&dp->dl_recall_lru); 20880af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 20891da177e4SLinus Torvalds } 20902d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 2091c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 20922d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 20936011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 2094956c4feeSBenny Halevy } 2095ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 2096fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 2097b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 2098fe0750e5SJ. Bruce Fields release_openowner(oo); 20991da177e4SLinus Torvalds } 210068ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 210168ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 210268ef3bc3SJeff Layton 210368ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 210468ef3bc3SJeff Layton so_strhash) { 210568ef3bc3SJeff Layton /* Should be no openowners at this point */ 210668ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 210768ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 210868ef3bc3SJeff Layton } 210968ef3bc3SJeff Layton } 21109cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 2111e0639dc5SOlga Kornievskaia nfsd4_shutdown_copy(clp); 21126ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 21132bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 21142bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 2115b12a05cbSJ. Bruce Fields free_client(clp); 211689c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 21171da177e4SLinus Torvalds } 21181da177e4SLinus Torvalds 21194beb345bSTrond Myklebust static void 21204beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 21214beb345bSTrond Myklebust { 21224beb345bSTrond Myklebust unhash_client(clp); 21234beb345bSTrond Myklebust __destroy_client(clp); 21244beb345bSTrond Myklebust } 21254beb345bSTrond Myklebust 2126362063a5SScott Mayhew static void inc_reclaim_complete(struct nfs4_client *clp) 2127362063a5SScott Mayhew { 2128362063a5SScott Mayhew struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2129362063a5SScott Mayhew 2130362063a5SScott Mayhew if (!nn->track_reclaim_completes) 2131362063a5SScott Mayhew return; 2132362063a5SScott Mayhew if (!nfsd4_find_reclaim_client(clp->cl_name, nn)) 2133362063a5SScott Mayhew return; 2134362063a5SScott Mayhew if (atomic_inc_return(&nn->nr_reclaim_complete) == 2135362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) { 2136362063a5SScott Mayhew printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n", 2137362063a5SScott Mayhew clp->net->ns.inum); 2138362063a5SScott Mayhew nfsd4_end_grace(nn); 2139362063a5SScott Mayhew } 2140362063a5SScott Mayhew } 2141362063a5SScott Mayhew 21420d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 21430d22f68fSJ. Bruce Fields { 21444beb345bSTrond Myklebust unhash_client(clp); 21450d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 21464beb345bSTrond Myklebust __destroy_client(clp); 21470d22f68fSJ. Bruce Fields } 21480d22f68fSJ. Bruce Fields 214935bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 215035bba9a3SJ. Bruce Fields { 215135bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 215235bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 21531da177e4SLinus Torvalds } 21541da177e4SLinus Torvalds 215535bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 215635bba9a3SJ. Bruce Fields { 21571da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 21581da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 21591da177e4SLinus Torvalds } 21601da177e4SLinus Torvalds 216150043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 216250043859SJ. Bruce Fields { 21632f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 21642f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 21652f10fdcbSNeilBrown GFP_KERNEL); 21669abdda5dSChuck Lever target->cr_targ_princ = kstrdup(source->cr_targ_princ, GFP_KERNEL); 21672f10fdcbSNeilBrown if ((source->cr_principal && !target->cr_principal) || 21689abdda5dSChuck Lever (source->cr_raw_principal && !target->cr_raw_principal) || 21699abdda5dSChuck Lever (source->cr_targ_princ && !target->cr_targ_princ)) 21702f10fdcbSNeilBrown return -ENOMEM; 217150043859SJ. Bruce Fields 2172d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 21731da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 21741da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 21751da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 21761da177e4SLinus Torvalds get_group_info(target->cr_group_info); 21770dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 21780dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 21790dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 218003a4e1f6SJ. Bruce Fields return 0; 21811da177e4SLinus Torvalds } 21821da177e4SLinus Torvalds 2183ef17af2aSRasmus Villemoes static int 2184ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 2185ac55fdc4SJeff Layton { 2186ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2187ef17af2aSRasmus Villemoes return -1; 2188ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2189ef17af2aSRasmus Villemoes return 1; 2190ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2191ac55fdc4SJeff Layton } 2192ac55fdc4SJeff Layton 21931da177e4SLinus Torvalds static int 2194599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2195599e0a22SJ. Bruce Fields { 2196599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 21971da177e4SLinus Torvalds } 21981da177e4SLinus Torvalds 21991da177e4SLinus Torvalds static int 2200599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2201599e0a22SJ. Bruce Fields { 2202599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 22031da177e4SLinus Torvalds } 22041da177e4SLinus Torvalds 22058fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 22068fbba96eSJ. Bruce Fields { 22078fbba96eSJ. Bruce Fields int i; 22088fbba96eSJ. Bruce Fields 22098fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 22108fbba96eSJ. Bruce Fields return false; 22118fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 221281243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 22138fbba96eSJ. Bruce Fields return false; 22148fbba96eSJ. Bruce Fields return true; 22158fbba96eSJ. Bruce Fields } 22168fbba96eSJ. Bruce Fields 221768eb3508SJ. Bruce Fields /* 221868eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 221968eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 222068eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 222168eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 222268eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 222368eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 222468eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 222568eb3508SJ. Bruce Fields */ 222668eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 222768eb3508SJ. Bruce Fields { 222868eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 222968eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 223068eb3508SJ. Bruce Fields } 223168eb3508SJ. Bruce Fields 223268eb3508SJ. Bruce Fields 22335559b50aSVivek Trivedi static bool 2234599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2235599e0a22SJ. Bruce Fields { 223668eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 22376fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 22386fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 22398fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 22408fbba96eSJ. Bruce Fields return false; 22419abdda5dSChuck Lever /* XXX: check that cr_targ_princ fields match ? */ 22428fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 22438fbba96eSJ. Bruce Fields return true; 22448fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 22458fbba96eSJ. Bruce Fields return false; 22465559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds 224957266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 225057266a6eSJ. Bruce Fields { 225157266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 225257266a6eSJ. Bruce Fields u32 service; 225357266a6eSJ. Bruce Fields 2254c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2255c4720591SJ. Bruce Fields return false; 225657266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 225757266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 225857266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 225957266a6eSJ. Bruce Fields } 226057266a6eSJ. Bruce Fields 2261dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 226257266a6eSJ. Bruce Fields { 226357266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 226457266a6eSJ. Bruce Fields 226557266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 226657266a6eSJ. Bruce Fields return true; 226757266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 226857266a6eSJ. Bruce Fields return false; 226957266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 227057266a6eSJ. Bruce Fields return false; 2271414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2272414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2273414ca017SJ. Bruce Fields cr->cr_raw_principal); 227457266a6eSJ. Bruce Fields if (!cr->cr_principal) 227557266a6eSJ. Bruce Fields return false; 227657266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 227757266a6eSJ. Bruce Fields } 227857266a6eSJ. Bruce Fields 2279294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2280deda2faaSJ. Bruce Fields { 2281ab4684d1SChuck Lever __be32 verf[2]; 22821da177e4SLinus Torvalds 2283f419992cSJeff Layton /* 2284f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2285f419992cSJeff Layton * __force to keep sparse happy 2286f419992cSJeff Layton */ 22879104ae49SArnd Bergmann verf[0] = (__force __be32)(u32)ktime_get_real_seconds(); 228819311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2289ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 22901da177e4SLinus Torvalds } 22911da177e4SLinus Torvalds 2292294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2293294ac32eSJeff Layton { 22949cc76801SArnd Bergmann clp->cl_clientid.cl_boot = (u32)nn->boot_time; 2295294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2296294ac32eSJeff Layton gen_confirm(clp, nn); 2297294ac32eSJeff Layton } 2298294ac32eSJeff Layton 22994770d722SJeff Layton static struct nfs4_stid * 23004770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 23014581d140SJ. Bruce Fields { 23023abdb607SJ. Bruce Fields struct nfs4_stid *ret; 23033abdb607SJ. Bruce Fields 23043abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 23053abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 23063abdb607SJ. Bruce Fields return NULL; 23073abdb607SJ. Bruce Fields return ret; 23084581d140SJ. Bruce Fields } 23094d71ab87SJ. Bruce Fields 23104770d722SJeff Layton static struct nfs4_stid * 23114770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2312f459e453SJ. Bruce Fields { 2313f459e453SJ. Bruce Fields struct nfs4_stid *s; 2314f459e453SJ. Bruce Fields 23154770d722SJeff Layton spin_lock(&cl->cl_lock); 23164770d722SJeff Layton s = find_stateid_locked(cl, t); 23172d3f9668STrond Myklebust if (s != NULL) { 23182d3f9668STrond Myklebust if (typemask & s->sc_type) 2319a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 23202d3f9668STrond Myklebust else 23214770d722SJeff Layton s = NULL; 23222d3f9668STrond Myklebust } 23234770d722SJeff Layton spin_unlock(&cl->cl_lock); 23244d71ab87SJ. Bruce Fields return s; 23254581d140SJ. Bruce Fields } 23264581d140SJ. Bruce Fields 2327a204f25eSJ. Bruce Fields static struct nfs4_client *get_nfsdfs_clp(struct inode *inode) 2328a204f25eSJ. Bruce Fields { 2329a204f25eSJ. Bruce Fields struct nfsdfs_client *nc; 2330a204f25eSJ. Bruce Fields nc = get_nfsdfs_client(inode); 2331a204f25eSJ. Bruce Fields if (!nc) 2332a204f25eSJ. Bruce Fields return NULL; 2333a204f25eSJ. Bruce Fields return container_of(nc, struct nfs4_client, cl_nfsdfs); 2334a204f25eSJ. Bruce Fields } 2335a204f25eSJ. Bruce Fields 2336169319f1SJ. Bruce Fields static void seq_quote_mem(struct seq_file *m, char *data, int len) 2337169319f1SJ. Bruce Fields { 2338169319f1SJ. Bruce Fields seq_printf(m, "\""); 2339169319f1SJ. Bruce Fields seq_escape_mem_ascii(m, data, len); 2340169319f1SJ. Bruce Fields seq_printf(m, "\""); 2341169319f1SJ. Bruce Fields } 2342169319f1SJ. Bruce Fields 234397ad4031SJ. Bruce Fields static int client_info_show(struct seq_file *m, void *v) 234497ad4031SJ. Bruce Fields { 234597ad4031SJ. Bruce Fields struct inode *inode = m->private; 234697ad4031SJ. Bruce Fields struct nfs4_client *clp; 234797ad4031SJ. Bruce Fields u64 clid; 234897ad4031SJ. Bruce Fields 2349a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2350a204f25eSJ. Bruce Fields if (!clp) 235197ad4031SJ. Bruce Fields return -ENXIO; 235297ad4031SJ. Bruce Fields memcpy(&clid, &clp->cl_clientid, sizeof(clid)); 235397ad4031SJ. Bruce Fields seq_printf(m, "clientid: 0x%llx\n", clid); 2354169319f1SJ. Bruce Fields seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); 2355169319f1SJ. Bruce Fields seq_printf(m, "name: "); 2356169319f1SJ. Bruce Fields seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); 2357169319f1SJ. Bruce Fields seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); 235879123444SJ. Bruce Fields if (clp->cl_nii_domain.data) { 235979123444SJ. Bruce Fields seq_printf(m, "Implementation domain: "); 236079123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_domain.data, 236179123444SJ. Bruce Fields clp->cl_nii_domain.len); 236279123444SJ. Bruce Fields seq_printf(m, "\nImplementation name: "); 236379123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_name.data, clp->cl_nii_name.len); 2364e29f4703SArnd Bergmann seq_printf(m, "\nImplementation time: [%lld, %ld]\n", 236579123444SJ. Bruce Fields clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); 236679123444SJ. Bruce Fields } 236797ad4031SJ. Bruce Fields drop_client(clp); 236897ad4031SJ. Bruce Fields 236997ad4031SJ. Bruce Fields return 0; 237097ad4031SJ. Bruce Fields } 237197ad4031SJ. Bruce Fields 237297ad4031SJ. Bruce Fields static int client_info_open(struct inode *inode, struct file *file) 237397ad4031SJ. Bruce Fields { 237497ad4031SJ. Bruce Fields return single_open(file, client_info_show, inode); 237597ad4031SJ. Bruce Fields } 237697ad4031SJ. Bruce Fields 237797ad4031SJ. Bruce Fields static const struct file_operations client_info_fops = { 237897ad4031SJ. Bruce Fields .open = client_info_open, 237997ad4031SJ. Bruce Fields .read = seq_read, 238097ad4031SJ. Bruce Fields .llseek = seq_lseek, 238197ad4031SJ. Bruce Fields .release = single_release, 238297ad4031SJ. Bruce Fields }; 238397ad4031SJ. Bruce Fields 238478599c42SJ. Bruce Fields static void *states_start(struct seq_file *s, loff_t *pos) 238578599c42SJ. Bruce Fields __acquires(&clp->cl_lock) 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 spin_lock(&clp->cl_lock); 239278599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 239378599c42SJ. Bruce Fields *pos = id; 239478599c42SJ. Bruce Fields return ret; 239578599c42SJ. Bruce Fields } 239678599c42SJ. Bruce Fields 239778599c42SJ. Bruce Fields static void *states_next(struct seq_file *s, void *v, loff_t *pos) 239878599c42SJ. Bruce Fields { 239978599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 240078599c42SJ. Bruce Fields unsigned long id = *pos; 240178599c42SJ. Bruce Fields void *ret; 240278599c42SJ. Bruce Fields 240378599c42SJ. Bruce Fields id = *pos; 240478599c42SJ. Bruce Fields id++; 240578599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 240678599c42SJ. Bruce Fields *pos = id; 240778599c42SJ. Bruce Fields return ret; 240878599c42SJ. Bruce Fields } 240978599c42SJ. Bruce Fields 241078599c42SJ. Bruce Fields static void states_stop(struct seq_file *s, void *v) 241178599c42SJ. Bruce Fields __releases(&clp->cl_lock) 241278599c42SJ. Bruce Fields { 241378599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 241478599c42SJ. Bruce Fields 241578599c42SJ. Bruce Fields spin_unlock(&clp->cl_lock); 241678599c42SJ. Bruce Fields } 241778599c42SJ. Bruce Fields 2418580da465SAchilles Gaikwad static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f) 2419580da465SAchilles Gaikwad { 2420580da465SAchilles Gaikwad seq_printf(s, "filename: \"%pD2\"", f->nf_file); 2421580da465SAchilles Gaikwad } 2422580da465SAchilles Gaikwad 2423fd4f83fdSJeff Layton static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) 242478599c42SJ. Bruce Fields { 2425fd4f83fdSJeff Layton struct inode *inode = f->nf_inode; 242678599c42SJ. Bruce Fields 242778599c42SJ. Bruce Fields seq_printf(s, "superblock: \"%02x:%02x:%ld\"", 242878599c42SJ. Bruce Fields MAJOR(inode->i_sb->s_dev), 242978599c42SJ. Bruce Fields MINOR(inode->i_sb->s_dev), 243078599c42SJ. Bruce Fields inode->i_ino); 243178599c42SJ. Bruce Fields } 243278599c42SJ. Bruce Fields 243378599c42SJ. Bruce Fields static void nfs4_show_owner(struct seq_file *s, struct nfs4_stateowner *oo) 243478599c42SJ. Bruce Fields { 243578599c42SJ. Bruce Fields seq_printf(s, "owner: "); 243678599c42SJ. Bruce Fields seq_quote_mem(s, oo->so_owner.data, oo->so_owner.len); 243778599c42SJ. Bruce Fields } 243878599c42SJ. Bruce Fields 2439ace7ade4SJ. Bruce Fields static void nfs4_show_stateid(struct seq_file *s, stateid_t *stid) 2440ace7ade4SJ. Bruce Fields { 2441ee590d25SJ. Bruce Fields seq_printf(s, "0x%.8x", stid->si_generation); 2442ee590d25SJ. Bruce Fields seq_printf(s, "%12phN", &stid->si_opaque); 2443ace7ade4SJ. Bruce Fields } 2444ace7ade4SJ. Bruce Fields 244578599c42SJ. Bruce Fields static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) 244678599c42SJ. Bruce Fields { 244778599c42SJ. Bruce Fields struct nfs4_ol_stateid *ols; 244878599c42SJ. Bruce Fields struct nfs4_file *nf; 2449fd4f83fdSJeff Layton struct nfsd_file *file; 245078599c42SJ. Bruce Fields struct nfs4_stateowner *oo; 245178599c42SJ. Bruce Fields unsigned int access, deny; 245278599c42SJ. Bruce Fields 245378599c42SJ. Bruce Fields if (st->sc_type != NFS4_OPEN_STID && st->sc_type != NFS4_LOCK_STID) 245478599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 245578599c42SJ. Bruce Fields ols = openlockstateid(st); 245678599c42SJ. Bruce Fields oo = ols->st_stateowner; 245778599c42SJ. Bruce Fields nf = st->sc_file; 245878599c42SJ. Bruce Fields file = find_any_file(nf); 24599affa435SJ. Bruce Fields if (!file) 24609affa435SJ. Bruce Fields return 0; 246178599c42SJ. Bruce Fields 2462ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2463ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2464ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: open, "); 246578599c42SJ. Bruce Fields 246678599c42SJ. Bruce Fields access = bmap_to_share_mode(ols->st_access_bmap); 246778599c42SJ. Bruce Fields deny = bmap_to_share_mode(ols->st_deny_bmap); 246878599c42SJ. Bruce Fields 2469c4b77edbSJ. Bruce Fields seq_printf(s, "access: %s%s, ", 247078599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_READ ? "r" : "-", 247178599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 2472c4b77edbSJ. Bruce Fields seq_printf(s, "deny: %s%s, ", 247378599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", 247478599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 247578599c42SJ. Bruce Fields 247678599c42SJ. Bruce Fields nfs4_show_superblock(s, file); 247778599c42SJ. Bruce Fields seq_printf(s, ", "); 2478580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2479580da465SAchilles Gaikwad seq_printf(s, ", "); 248078599c42SJ. Bruce Fields nfs4_show_owner(s, oo); 248178599c42SJ. Bruce Fields seq_printf(s, " }\n"); 2482fd4f83fdSJeff Layton nfsd_file_put(file); 248378599c42SJ. Bruce Fields 248478599c42SJ. Bruce Fields return 0; 248578599c42SJ. Bruce Fields } 248678599c42SJ. Bruce Fields 248716d36e09SJ. Bruce Fields static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) 248816d36e09SJ. Bruce Fields { 248916d36e09SJ. Bruce Fields struct nfs4_ol_stateid *ols; 249016d36e09SJ. Bruce Fields struct nfs4_file *nf; 2491fd4f83fdSJeff Layton struct nfsd_file *file; 249216d36e09SJ. Bruce Fields struct nfs4_stateowner *oo; 249316d36e09SJ. Bruce Fields 249416d36e09SJ. Bruce Fields ols = openlockstateid(st); 249516d36e09SJ. Bruce Fields oo = ols->st_stateowner; 249616d36e09SJ. Bruce Fields nf = st->sc_file; 249716d36e09SJ. Bruce Fields file = find_any_file(nf); 24989affa435SJ. Bruce Fields if (!file) 24999affa435SJ. Bruce Fields return 0; 250016d36e09SJ. Bruce Fields 2501ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2502ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2503ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: lock, "); 250416d36e09SJ. Bruce Fields 250516d36e09SJ. Bruce Fields /* 250616d36e09SJ. Bruce Fields * Note: a lock stateid isn't really the same thing as a lock, 250716d36e09SJ. Bruce Fields * it's the locking state held by one owner on a file, and there 250816d36e09SJ. Bruce Fields * may be multiple (or no) lock ranges associated with it. 250916d36e09SJ. Bruce Fields * (Same for the matter is true of open stateids.) 251016d36e09SJ. Bruce Fields */ 251116d36e09SJ. Bruce Fields 251216d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 251316d36e09SJ. Bruce Fields /* XXX: open stateid? */ 251416d36e09SJ. Bruce Fields seq_printf(s, ", "); 2515580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2516580da465SAchilles Gaikwad seq_printf(s, ", "); 251716d36e09SJ. Bruce Fields nfs4_show_owner(s, oo); 251816d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2519fd4f83fdSJeff Layton nfsd_file_put(file); 252016d36e09SJ. Bruce Fields 252116d36e09SJ. Bruce Fields return 0; 252216d36e09SJ. Bruce Fields } 252316d36e09SJ. Bruce Fields 252416d36e09SJ. Bruce Fields static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) 252516d36e09SJ. Bruce Fields { 252616d36e09SJ. Bruce Fields struct nfs4_delegation *ds; 252716d36e09SJ. Bruce Fields struct nfs4_file *nf; 2528eb82dd39SJeff Layton struct nfsd_file *file; 252916d36e09SJ. Bruce Fields 253016d36e09SJ. Bruce Fields ds = delegstateid(st); 253116d36e09SJ. Bruce Fields nf = st->sc_file; 25329affa435SJ. Bruce Fields file = find_deleg_file(nf); 25339affa435SJ. Bruce Fields if (!file) 25349affa435SJ. Bruce Fields return 0; 253516d36e09SJ. Bruce Fields 2536ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2537ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2538ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: deleg, "); 253916d36e09SJ. Bruce Fields 254016d36e09SJ. Bruce Fields /* Kinda dead code as long as we only support read delegs: */ 254116d36e09SJ. Bruce Fields seq_printf(s, "access: %s, ", 254216d36e09SJ. Bruce Fields ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); 254316d36e09SJ. Bruce Fields 254416d36e09SJ. Bruce Fields /* XXX: lease time, whether it's being recalled. */ 254516d36e09SJ. Bruce Fields 254616d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 2547580da465SAchilles Gaikwad seq_printf(s, ", "); 2548580da465SAchilles Gaikwad nfs4_show_fname(s, file); 254916d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 25509affa435SJ. Bruce Fields nfsd_file_put(file); 255116d36e09SJ. Bruce Fields 255216d36e09SJ. Bruce Fields return 0; 255316d36e09SJ. Bruce Fields } 255416d36e09SJ. Bruce Fields 25550c4b62b0SJ. Bruce Fields static int nfs4_show_layout(struct seq_file *s, struct nfs4_stid *st) 25560c4b62b0SJ. Bruce Fields { 25570c4b62b0SJ. Bruce Fields struct nfs4_layout_stateid *ls; 2558eb82dd39SJeff Layton struct nfsd_file *file; 25590c4b62b0SJ. Bruce Fields 25600c4b62b0SJ. Bruce Fields ls = container_of(st, struct nfs4_layout_stateid, ls_stid); 25610c4b62b0SJ. Bruce Fields file = ls->ls_file; 25620c4b62b0SJ. Bruce Fields 2563ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2564ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2565ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: layout, "); 25660c4b62b0SJ. Bruce Fields 25670c4b62b0SJ. Bruce Fields /* XXX: What else would be useful? */ 25680c4b62b0SJ. Bruce Fields 25690c4b62b0SJ. Bruce Fields nfs4_show_superblock(s, file); 2570580da465SAchilles Gaikwad seq_printf(s, ", "); 2571580da465SAchilles Gaikwad nfs4_show_fname(s, file); 25720c4b62b0SJ. Bruce Fields seq_printf(s, " }\n"); 25730c4b62b0SJ. Bruce Fields 25740c4b62b0SJ. Bruce Fields return 0; 25750c4b62b0SJ. Bruce Fields } 25760c4b62b0SJ. Bruce Fields 257778599c42SJ. Bruce Fields static int states_show(struct seq_file *s, void *v) 257878599c42SJ. Bruce Fields { 257978599c42SJ. Bruce Fields struct nfs4_stid *st = v; 258078599c42SJ. Bruce Fields 258178599c42SJ. Bruce Fields switch (st->sc_type) { 258278599c42SJ. Bruce Fields case NFS4_OPEN_STID: 258378599c42SJ. Bruce Fields return nfs4_show_open(s, st); 258416d36e09SJ. Bruce Fields case NFS4_LOCK_STID: 258516d36e09SJ. Bruce Fields return nfs4_show_lock(s, st); 258616d36e09SJ. Bruce Fields case NFS4_DELEG_STID: 258716d36e09SJ. Bruce Fields return nfs4_show_deleg(s, st); 25880c4b62b0SJ. Bruce Fields case NFS4_LAYOUT_STID: 25890c4b62b0SJ. Bruce Fields return nfs4_show_layout(s, st); 259078599c42SJ. Bruce Fields default: 259178599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 259278599c42SJ. Bruce Fields } 259316d36e09SJ. Bruce Fields /* XXX: copy stateids? */ 259478599c42SJ. Bruce Fields } 259578599c42SJ. Bruce Fields 259678599c42SJ. Bruce Fields static struct seq_operations states_seq_ops = { 259778599c42SJ. Bruce Fields .start = states_start, 259878599c42SJ. Bruce Fields .next = states_next, 259978599c42SJ. Bruce Fields .stop = states_stop, 260078599c42SJ. Bruce Fields .show = states_show 260178599c42SJ. Bruce Fields }; 260278599c42SJ. Bruce Fields 260378599c42SJ. Bruce Fields static int client_states_open(struct inode *inode, struct file *file) 260478599c42SJ. Bruce Fields { 260578599c42SJ. Bruce Fields struct seq_file *s; 260678599c42SJ. Bruce Fields struct nfs4_client *clp; 260778599c42SJ. Bruce Fields int ret; 260878599c42SJ. Bruce Fields 2609a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2610a204f25eSJ. Bruce Fields if (!clp) 261178599c42SJ. Bruce Fields return -ENXIO; 261278599c42SJ. Bruce Fields 261378599c42SJ. Bruce Fields ret = seq_open(file, &states_seq_ops); 261478599c42SJ. Bruce Fields if (ret) 261578599c42SJ. Bruce Fields return ret; 261678599c42SJ. Bruce Fields s = file->private_data; 261778599c42SJ. Bruce Fields s->private = clp; 261878599c42SJ. Bruce Fields return 0; 261978599c42SJ. Bruce Fields } 262078599c42SJ. Bruce Fields 262178599c42SJ. Bruce Fields static int client_opens_release(struct inode *inode, struct file *file) 262278599c42SJ. Bruce Fields { 262378599c42SJ. Bruce Fields struct seq_file *m = file->private_data; 262478599c42SJ. Bruce Fields struct nfs4_client *clp = m->private; 262578599c42SJ. Bruce Fields 262678599c42SJ. Bruce Fields /* XXX: alternatively, we could get/drop in seq start/stop */ 262778599c42SJ. Bruce Fields drop_client(clp); 262878599c42SJ. Bruce Fields return 0; 262978599c42SJ. Bruce Fields } 263078599c42SJ. Bruce Fields 263178599c42SJ. Bruce Fields static const struct file_operations client_states_fops = { 263278599c42SJ. Bruce Fields .open = client_states_open, 263378599c42SJ. Bruce Fields .read = seq_read, 263478599c42SJ. Bruce Fields .llseek = seq_lseek, 263578599c42SJ. Bruce Fields .release = client_opens_release, 263678599c42SJ. Bruce Fields }; 263778599c42SJ. Bruce Fields 263889c905beSJ. Bruce Fields /* 263989c905beSJ. Bruce Fields * Normally we refuse to destroy clients that are in use, but here the 264089c905beSJ. Bruce Fields * administrator is telling us to just do it. We also want to wait 264189c905beSJ. Bruce Fields * so the caller has a guarantee that the client's locks are gone by 264289c905beSJ. Bruce Fields * the time the write returns: 264389c905beSJ. Bruce Fields */ 2644297e57a2SYueHaibing static void force_expire_client(struct nfs4_client *clp) 264589c905beSJ. Bruce Fields { 264689c905beSJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 264789c905beSJ. Bruce Fields bool already_expired; 264889c905beSJ. Bruce Fields 264989c905beSJ. Bruce Fields spin_lock(&clp->cl_lock); 265089c905beSJ. Bruce Fields clp->cl_time = 0; 265189c905beSJ. Bruce Fields spin_unlock(&clp->cl_lock); 265289c905beSJ. Bruce Fields 265389c905beSJ. Bruce Fields wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0); 265489c905beSJ. Bruce Fields spin_lock(&nn->client_lock); 265589c905beSJ. Bruce Fields already_expired = list_empty(&clp->cl_lru); 265689c905beSJ. Bruce Fields if (!already_expired) 265789c905beSJ. Bruce Fields unhash_client_locked(clp); 265889c905beSJ. Bruce Fields spin_unlock(&nn->client_lock); 265989c905beSJ. Bruce Fields 266089c905beSJ. Bruce Fields if (!already_expired) 266189c905beSJ. Bruce Fields expire_client(clp); 266289c905beSJ. Bruce Fields else 266389c905beSJ. Bruce Fields wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL); 266489c905beSJ. Bruce Fields } 266589c905beSJ. Bruce Fields 266689c905beSJ. Bruce Fields static ssize_t client_ctl_write(struct file *file, const char __user *buf, 266789c905beSJ. Bruce Fields size_t size, loff_t *pos) 266889c905beSJ. Bruce Fields { 266989c905beSJ. Bruce Fields char *data; 267089c905beSJ. Bruce Fields struct nfs4_client *clp; 267189c905beSJ. Bruce Fields 267289c905beSJ. Bruce Fields data = simple_transaction_get(file, buf, size); 267389c905beSJ. Bruce Fields if (IS_ERR(data)) 267489c905beSJ. Bruce Fields return PTR_ERR(data); 267589c905beSJ. Bruce Fields if (size != 7 || 0 != memcmp(data, "expire\n", 7)) 267689c905beSJ. Bruce Fields return -EINVAL; 267789c905beSJ. Bruce Fields clp = get_nfsdfs_clp(file_inode(file)); 267889c905beSJ. Bruce Fields if (!clp) 267989c905beSJ. Bruce Fields return -ENXIO; 268089c905beSJ. Bruce Fields force_expire_client(clp); 268189c905beSJ. Bruce Fields drop_client(clp); 268289c905beSJ. Bruce Fields return 7; 268389c905beSJ. Bruce Fields } 268489c905beSJ. Bruce Fields 268589c905beSJ. Bruce Fields static const struct file_operations client_ctl_fops = { 268689c905beSJ. Bruce Fields .write = client_ctl_write, 268789c905beSJ. Bruce Fields .release = simple_transaction_release, 268889c905beSJ. Bruce Fields }; 268989c905beSJ. Bruce Fields 269097ad4031SJ. Bruce Fields static const struct tree_descr client_files[] = { 269197ad4031SJ. Bruce Fields [0] = {"info", &client_info_fops, S_IRUSR}, 269278599c42SJ. Bruce Fields [1] = {"states", &client_states_fops, S_IRUSR}, 26936cbfad5fSPetr Vorel [2] = {"ctl", &client_ctl_fops, S_IWUSR}, 269478599c42SJ. Bruce Fields [3] = {""}, 269597ad4031SJ. Bruce Fields }; 269697ad4031SJ. Bruce Fields 26972216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2698b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2699b09333c4SRicardo Labiaga { 2700b09333c4SRicardo Labiaga struct nfs4_client *clp; 2701b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 270203a4e1f6SJ. Bruce Fields int ret; 2703c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2704e8a79fb1SJ. Bruce Fields struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2705b09333c4SRicardo Labiaga 2706b09333c4SRicardo Labiaga clp = alloc_client(name); 2707b09333c4SRicardo Labiaga if (clp == NULL) 2708b09333c4SRicardo Labiaga return NULL; 2709b09333c4SRicardo Labiaga 271003a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 271103a4e1f6SJ. Bruce Fields if (ret) { 2712b09333c4SRicardo Labiaga free_client(clp); 2713b09333c4SRicardo Labiaga return NULL; 2714b09333c4SRicardo Labiaga } 2715e8a79fb1SJ. Bruce Fields gen_clid(clp, nn); 2716e8a79fb1SJ. Bruce Fields kref_init(&clp->cl_nfsdfs.cl_ref); 27170162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 271820b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 2719b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2720b09333c4SRicardo Labiaga copy_verf(clp, verf); 27213bade247SJ. Bruce Fields memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); 2722edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2723c212cecfSStanislav Kinsbursky clp->net = net; 2724e8a79fb1SJ. Bruce Fields clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs, 272597ad4031SJ. Bruce Fields clp->cl_clientid.cl_id - nn->clientid_base, 272697ad4031SJ. Bruce Fields client_files); 2727e8a79fb1SJ. Bruce Fields if (!clp->cl_nfsd_dentry) { 2728e8a79fb1SJ. Bruce Fields free_client(clp); 2729e8a79fb1SJ. Bruce Fields return NULL; 2730e8a79fb1SJ. Bruce Fields } 2731b09333c4SRicardo Labiaga return clp; 2732b09333c4SRicardo Labiaga } 2733b09333c4SRicardo Labiaga 2734fd39ca9aSNeilBrown static void 2735ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2736ac55fdc4SJeff Layton { 2737ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2738ac55fdc4SJeff Layton struct nfs4_client *clp; 2739ac55fdc4SJeff Layton 2740ac55fdc4SJeff Layton while (*new) { 2741ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2742ac55fdc4SJeff Layton parent = *new; 2743ac55fdc4SJeff Layton 2744ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2745ac55fdc4SJeff Layton new = &((*new)->rb_left); 2746ac55fdc4SJeff Layton else 2747ac55fdc4SJeff Layton new = &((*new)->rb_right); 2748ac55fdc4SJeff Layton } 2749ac55fdc4SJeff Layton 2750ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2751ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2752ac55fdc4SJeff Layton } 2753ac55fdc4SJeff Layton 2754ac55fdc4SJeff Layton static struct nfs4_client * 2755ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2756ac55fdc4SJeff Layton { 2757ef17af2aSRasmus Villemoes int cmp; 2758ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2759ac55fdc4SJeff Layton struct nfs4_client *clp; 2760ac55fdc4SJeff Layton 2761ac55fdc4SJeff Layton while (node) { 2762ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2763ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2764ac55fdc4SJeff Layton if (cmp > 0) 2765ac55fdc4SJeff Layton node = node->rb_left; 2766ac55fdc4SJeff Layton else if (cmp < 0) 2767ac55fdc4SJeff Layton node = node->rb_right; 2768ac55fdc4SJeff Layton else 2769ac55fdc4SJeff Layton return clp; 2770ac55fdc4SJeff Layton } 2771ac55fdc4SJeff Layton return NULL; 2772ac55fdc4SJeff Layton } 2773ac55fdc4SJeff Layton 2774ac55fdc4SJeff Layton static void 2775ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 27761da177e4SLinus Torvalds { 27771da177e4SLinus Torvalds unsigned int idhashval; 27780a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 27791da177e4SLinus Torvalds 27800a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 27810a880a28STrond Myklebust 2782ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2783a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 27841da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 27850a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 27863dbacee6STrond Myklebust renew_client_locked(clp); 27871da177e4SLinus Torvalds } 27881da177e4SLinus Torvalds 2789fd39ca9aSNeilBrown static void 27901da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 27911da177e4SLinus Torvalds { 27921da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 27938daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 27941da177e4SLinus Torvalds 27950a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 27960a880a28STrond Myklebust 27971da177e4SLinus Torvalds dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); 27988daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2799a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2800382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2801ac55fdc4SJeff Layton set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 28023dbacee6STrond Myklebust renew_client_locked(clp); 28031da177e4SLinus Torvalds } 28041da177e4SLinus Torvalds 28051da177e4SLinus Torvalds static struct nfs4_client * 2806bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 28071da177e4SLinus Torvalds { 28081da177e4SLinus Torvalds struct nfs4_client *clp; 28091da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 28101da177e4SLinus Torvalds 2811bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2812a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2813d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2814d15c077eSJ. Bruce Fields return NULL; 28153dbacee6STrond Myklebust renew_client_locked(clp); 28161da177e4SLinus Torvalds return clp; 28171da177e4SLinus Torvalds } 2818a50d2ad1SJ. Bruce Fields } 28191da177e4SLinus Torvalds return NULL; 28201da177e4SLinus Torvalds } 28211da177e4SLinus Torvalds 28221da177e4SLinus Torvalds static struct nfs4_client * 2823bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2824bfa85e83SJ. Bruce Fields { 2825bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2826bfa85e83SJ. Bruce Fields 28270a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2828bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2829bfa85e83SJ. Bruce Fields } 2830bfa85e83SJ. Bruce Fields 2831bfa85e83SJ. Bruce Fields static struct nfs4_client * 28320a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 28331da177e4SLinus Torvalds { 2834bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 28351da177e4SLinus Torvalds 28360a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2837bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 28381da177e4SLinus Torvalds } 28391da177e4SLinus Torvalds 28406e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2841a1bcecd2SAndy Adamson { 28426e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2843a1bcecd2SAndy Adamson } 2844a1bcecd2SAndy Adamson 284528ce6054SNeilBrown static struct nfs4_client * 2846382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 284728ce6054SNeilBrown { 28480a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2849382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 285028ce6054SNeilBrown } 285128ce6054SNeilBrown 285228ce6054SNeilBrown static struct nfs4_client * 2853a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 285428ce6054SNeilBrown { 28550a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2856a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 285728ce6054SNeilBrown } 285828ce6054SNeilBrown 2859fd39ca9aSNeilBrown static void 28606f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 28611da177e4SLinus Torvalds { 286207263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 28636f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 28646f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 28657077ecbaSJeff Layton unsigned short expected_family; 28661da177e4SLinus Torvalds 28677077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 28687077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 28697077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 28707077ecbaSJeff Layton expected_family = AF_INET; 28717077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 28727077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 28737077ecbaSJeff Layton expected_family = AF_INET6; 28747077ecbaSJeff Layton else 28751da177e4SLinus Torvalds goto out_err; 28761da177e4SLinus Torvalds 2877c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 2878aa9a4ec7SJeff Layton se->se_callback_addr_len, 287907263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 288007263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 2881aa9a4ec7SJeff Layton 288207263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 28831da177e4SLinus Torvalds goto out_err; 2884aa9a4ec7SJeff Layton 288507263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 288607263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 2887fbf4665fSJeff Layton 288807263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 288907263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 2890849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 28911eace0d1SChuck Lever trace_nfsd_cb_args(clp, conn); 28921da177e4SLinus Torvalds return; 28931da177e4SLinus Torvalds out_err: 289407263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 289507263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 28961eace0d1SChuck Lever trace_nfsd_cb_nodelegs(clp); 28971da177e4SLinus Torvalds return; 28981da177e4SLinus Torvalds } 28991da177e4SLinus Torvalds 2900074fe897SAndy Adamson /* 2901067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 2902074fe897SAndy Adamson */ 2903b607664eSTrond Myklebust static void 2904074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 2905074fe897SAndy Adamson { 2906f5236013SJ. Bruce Fields struct xdr_buf *buf = resp->xdr.buf; 2907557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2908557ce264SAndy Adamson unsigned int base; 2909074fe897SAndy Adamson 2910557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2911074fe897SAndy Adamson 2912085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 2913557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 2914557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 291553da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 291653da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 2917bf864a31SAndy Adamson 2918085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 2919085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 2920bf864a31SAndy Adamson return; 2921bf864a31SAndy Adamson } 2922085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 2923085def3aSJ. Bruce Fields 2924f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 2925f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 2926f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 2927d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 2928d3f03403SDan Carpenter __func__); 2929557ce264SAndy Adamson return; 2930074fe897SAndy Adamson } 2931074fe897SAndy Adamson 2932074fe897SAndy Adamson /* 2933abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 2934abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 2935abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 2936abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 2937abfabf8cSAndy Adamson * 2938074fe897SAndy Adamson */ 2939abfabf8cSAndy Adamson static __be32 2940abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 2941abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 2942074fe897SAndy Adamson { 2943abfabf8cSAndy Adamson struct nfsd4_op *op; 2944abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2945074fe897SAndy Adamson 2946abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 2947abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 2948abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2949abfabf8cSAndy Adamson 2950085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 2951085def3aSJ. Bruce Fields return op->status; 2952085def3aSJ. Bruce Fields if (args->opcnt == 1) { 2953085def3aSJ. Bruce Fields /* 2954085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 2955085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 2956085def3aSJ. Bruce Fields * original: 2957085def3aSJ. Bruce Fields */ 2958085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 2959085def3aSJ. Bruce Fields } else { 2960abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 2961abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 2962abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 2963074fe897SAndy Adamson } 2964abfabf8cSAndy Adamson return op->status; 2965074fe897SAndy Adamson } 2966074fe897SAndy Adamson 2967074fe897SAndy Adamson /* 2968557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 2969557ce264SAndy Adamson * session values. 2970074fe897SAndy Adamson */ 29713ca2eb98SJ. Bruce Fields static __be32 2972bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 2973bf864a31SAndy Adamson struct nfsd4_sequence *seq) 2974074fe897SAndy Adamson { 2975557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 2976f5236013SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 2977f5236013SJ. Bruce Fields __be32 *p; 2978074fe897SAndy Adamson __be32 status; 2979074fe897SAndy Adamson 2980557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 2981074fe897SAndy Adamson 2982abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 29830da7b19cSJ. Bruce Fields if (status) 2984abfabf8cSAndy Adamson return status; 2985074fe897SAndy Adamson 2986f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 2987f5236013SJ. Bruce Fields if (!p) { 2988f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 2989f5236013SJ. Bruce Fields return nfserr_serverfault; 2990f5236013SJ. Bruce Fields } 2991f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 2992f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 2993074fe897SAndy Adamson 2994557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 2995f5236013SJ. Bruce Fields return slot->sl_status; 2996074fe897SAndy Adamson } 2997074fe897SAndy Adamson 29980733d213SAndy Adamson /* 29990733d213SAndy Adamson * Set the exchange_id flags returned by the server. 30000733d213SAndy Adamson */ 30010733d213SAndy Adamson static void 30020733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 30030733d213SAndy Adamson { 30049cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 30059cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 30069cf514ccSChristoph Hellwig #else 30070733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 30089cf514ccSChristoph Hellwig #endif 30090733d213SAndy Adamson 30100733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 30110733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 30120733d213SAndy Adamson 30130733d213SAndy Adamson /* set the wire flags to return to client. */ 30140733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 30150733d213SAndy Adamson } 30160733d213SAndy Adamson 30174eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 30184eaea134SJ. Bruce Fields { 30194eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 30204eaea134SJ. Bruce Fields 30214eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 30224eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 30234eaea134SJ. Bruce Fields return true; 30244eaea134SJ. Bruce Fields } 30254eaea134SJ. Bruce Fields return false; 30264eaea134SJ. Bruce Fields } 30274eaea134SJ. Bruce Fields 3028631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 3029631fc9eaSJ. Bruce Fields { 30304eaea134SJ. Bruce Fields return client_has_openowners(clp) 303147e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 303247e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 303347e970beSKinglong Mee #endif 30346eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 3035e0639dc5SOlga Kornievskaia || !list_empty(&clp->cl_sessions) 3036e0639dc5SOlga Kornievskaia || !list_empty(&clp->async_copies); 3037631fc9eaSJ. Bruce Fields } 3038631fc9eaSJ. Bruce Fields 303979123444SJ. Bruce Fields static __be32 copy_impl_id(struct nfs4_client *clp, 304079123444SJ. Bruce Fields struct nfsd4_exchange_id *exid) 304179123444SJ. Bruce Fields { 304279123444SJ. Bruce Fields if (!exid->nii_domain.data) 304379123444SJ. Bruce Fields return 0; 304479123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_domain, &exid->nii_domain, GFP_KERNEL); 304579123444SJ. Bruce Fields if (!clp->cl_nii_domain.data) 304679123444SJ. Bruce Fields return nfserr_jukebox; 304779123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_name, &exid->nii_name, GFP_KERNEL); 304879123444SJ. Bruce Fields if (!clp->cl_nii_name.data) 304979123444SJ. Bruce Fields return nfserr_jukebox; 3050e29f4703SArnd Bergmann clp->cl_nii_time = exid->nii_time; 305179123444SJ. Bruce Fields return 0; 305279123444SJ. Bruce Fields } 305379123444SJ. Bruce Fields 3054b37ad28bSAl Viro __be32 3055eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3056eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3057069b6ad4SAndy Adamson { 3058eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 30593dbacee6STrond Myklebust struct nfs4_client *conf, *new; 30603dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 306157b7b43bSJ. Bruce Fields __be32 status; 3062363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 30630733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 3064363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 306583e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 3066c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 30670733d213SAndy Adamson 3068363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 30690733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 3070523ec6edSChuck Lever "ip_addr=%s flags %x, spa_how %u\n", 30710733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 3072363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 30730733d213SAndy Adamson 3074a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 30750733d213SAndy Adamson return nfserr_inval; 30760733d213SAndy Adamson 307750c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 307850c7b948SJ. Bruce Fields if (new == NULL) 307950c7b948SJ. Bruce Fields return nfserr_jukebox; 308079123444SJ. Bruce Fields status = copy_impl_id(new, exid); 308179123444SJ. Bruce Fields if (status) 308279123444SJ. Bruce Fields goto out_nolock; 308350c7b948SJ. Bruce Fields 30840733d213SAndy Adamson switch (exid->spa_how) { 308557266a6eSJ. Bruce Fields case SP4_MACH_CRED: 3086ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 3087ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 3088ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 3089ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 3090ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 3091ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 3092ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 3093ed941643SAndrew Elble 3094ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 3095ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 3096ed941643SAndrew Elble 1 << (OP_LOCKU) | 3097ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 3098ed941643SAndrew Elble 3099ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 3100ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 3101ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 310250c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 310350c7b948SJ. Bruce Fields status = nfserr_inval; 310450c7b948SJ. Bruce Fields goto out_nolock; 310550c7b948SJ. Bruce Fields } 3106920dd9bbSJ. Bruce Fields /* 3107920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 3108920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 3109920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 3110920dd9bbSJ. Bruce Fields */ 3111414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 3112414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 3113920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 3114920dd9bbSJ. Bruce Fields goto out_nolock; 3115920dd9bbSJ. Bruce Fields } 311650c7b948SJ. Bruce Fields new->cl_mach_cred = true; 31170733d213SAndy Adamson case SP4_NONE: 31180733d213SAndy Adamson break; 3119063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 3120063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 3121df561f66SGustavo A. R. Silva fallthrough; 31220733d213SAndy Adamson case SP4_SSV: 31238edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 31248edf4b02SKinglong Mee goto out_nolock; 31250733d213SAndy Adamson } 31260733d213SAndy Adamson 31272dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 31283dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3129382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 31300733d213SAndy Adamson if (conf) { 313183e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 313283e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 313383e08fd4SJ. Bruce Fields 3134136e658dSJ. Bruce Fields if (update) { 3135136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 31362dbb269dSJ. Bruce Fields status = nfserr_inval; 3137e203d506SJ. Bruce Fields goto out; 3138e203d506SJ. Bruce Fields } 3139dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 314057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 314157266a6eSJ. Bruce Fields goto out; 314257266a6eSJ. Bruce Fields } 31432dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 31440733d213SAndy Adamson status = nfserr_perm; 31450733d213SAndy Adamson goto out; 31460733d213SAndy Adamson } 31472dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 31480733d213SAndy Adamson status = nfserr_not_same; 31490733d213SAndy Adamson goto out; 31500733d213SAndy Adamson } 3151136e658dSJ. Bruce Fields /* case 6 */ 31520733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 31530733d213SAndy Adamson goto out_copy; 31546ddbbbfeSMike Sager } 3155136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 3156631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 3157136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 3158136e658dSJ. Bruce Fields goto out; 3159136e658dSJ. Bruce Fields } 3160b9831b59SJ. Bruce Fields goto out_new; 3161631fc9eaSJ. Bruce Fields } 3162136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 31630f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 3164136e658dSJ. Bruce Fields goto out_copy; 3165136e658dSJ. Bruce Fields } 31662dbb269dSJ. Bruce Fields /* case 5, client reboot */ 31673dbacee6STrond Myklebust conf = NULL; 31680733d213SAndy Adamson goto out_new; 31690733d213SAndy Adamson } 31706ddbbbfeSMike Sager 31712dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 31720733d213SAndy Adamson status = nfserr_noent; 31730733d213SAndy Adamson goto out; 31740733d213SAndy Adamson } 31750733d213SAndy Adamson 3176a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 31772dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 31783dbacee6STrond Myklebust unhash_client_locked(unconf); 31790733d213SAndy Adamson 31802dbb269dSJ. Bruce Fields /* case 1 (normal case) */ 31810733d213SAndy Adamson out_new: 3182fd699b8aSJeff Layton if (conf) { 3183fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3184fd699b8aSJeff Layton if (status) 3185fd699b8aSJeff Layton goto out; 3186fd699b8aSJeff Layton } 31874f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 3188ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 3189ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 31900733d213SAndy Adamson 3191ac55fdc4SJeff Layton add_to_unconfirmed(new); 31923dbacee6STrond Myklebust swap(new, conf); 31930733d213SAndy Adamson out_copy: 31945cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 31955cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 31960733d213SAndy Adamson 31975cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 31985cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 31990733d213SAndy Adamson 32000733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 32015cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 32020733d213SAndy Adamson status = nfs_ok; 32030733d213SAndy Adamson 32040733d213SAndy Adamson out: 32053dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 320650c7b948SJ. Bruce Fields out_nolock: 32075cc40fd7STrond Myklebust if (new) 32083dbacee6STrond Myklebust expire_client(new); 32093dbacee6STrond Myklebust if (unconf) 32103dbacee6STrond Myklebust expire_client(unconf); 32110733d213SAndy Adamson return status; 3212069b6ad4SAndy Adamson } 3213069b6ad4SAndy Adamson 321457b7b43bSJ. Bruce Fields static __be32 321588e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 3216b85d4c01SBenny Halevy { 321788e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 321888e588d5SAndy Adamson slot_seqid); 3219b85d4c01SBenny Halevy 3220b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 322188e588d5SAndy Adamson if (slot_inuse) { 322288e588d5SAndy Adamson if (seqid == slot_seqid) 3223b85d4c01SBenny Halevy return nfserr_jukebox; 3224b85d4c01SBenny Halevy else 3225b85d4c01SBenny Halevy return nfserr_seq_misordered; 3226b85d4c01SBenny Halevy } 3227f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 322888e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 3229b85d4c01SBenny Halevy return nfs_ok; 323088e588d5SAndy Adamson if (seqid == slot_seqid) 3231b85d4c01SBenny Halevy return nfserr_replay_cache; 3232b85d4c01SBenny Halevy return nfserr_seq_misordered; 3233b85d4c01SBenny Halevy } 3234b85d4c01SBenny Halevy 323549557cc7SAndy Adamson /* 323649557cc7SAndy Adamson * Cache the create session result into the create session single DRC 323749557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 323849557cc7SAndy Adamson * Do this for solo or embedded create session operations. 323949557cc7SAndy Adamson */ 324049557cc7SAndy Adamson static void 324149557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 324257b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 324349557cc7SAndy Adamson { 324449557cc7SAndy Adamson slot->sl_status = nfserr; 324549557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 324649557cc7SAndy Adamson } 324749557cc7SAndy Adamson 324849557cc7SAndy Adamson static __be32 324949557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 325049557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 325149557cc7SAndy Adamson { 325249557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 325349557cc7SAndy Adamson return slot->sl_status; 325449557cc7SAndy Adamson } 325549557cc7SAndy Adamson 32561b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 32571b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 32581b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 32591b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 32601b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 32611b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 32621b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 32631b74c25bSMi Jinlong 32641b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 32651b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 32661b74c25bSMi Jinlong 1 + /* status */ \ 32671b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 32681b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 32691b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 32701b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 32711b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 32721b74c25bSMi Jinlong 327355c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 32741b74c25bSMi Jinlong { 327555c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 327655c760cfSJ. Bruce Fields 3277373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 3278373cd409SJ. Bruce Fields return nfserr_toosmall; 3279373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 3280373cd409SJ. Bruce Fields return nfserr_toosmall; 328155c760cfSJ. Bruce Fields ca->headerpadsz = 0; 328255c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 328355c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 328455c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 328555c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 328655c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 328755c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 328855c760cfSJ. Bruce Fields /* 328955c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 329055c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 329155c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 329255c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 329355c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 329455c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 32957f49fd5dSNeilBrown * Note that we always allow at least one slot, because our 32967f49fd5dSNeilBrown * accounting is soft and provides no guarantees either way. 329755c760cfSJ. Bruce Fields */ 32982030ca56SNeilBrown ca->maxreqs = nfsd4_get_drc_mem(ca, nn); 329955c760cfSJ. Bruce Fields 3300373cd409SJ. Bruce Fields return nfs_ok; 33011b74c25bSMi Jinlong } 33021b74c25bSMi Jinlong 33034500632fSChuck Lever /* 33044500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 33054500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 33064500632fSChuck Lever */ 33074500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 33084500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 33094500632fSChuck Lever 33104500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 33114500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 33124500632fSChuck Lever 33138a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 33144500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 33158a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 33164500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 33174500632fSChuck Lever sizeof(__be32)) 33188a891633SKinglong Mee 331906b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 332006b332a5SJ. Bruce Fields { 332106b332a5SJ. Bruce Fields ca->headerpadsz = 0; 332206b332a5SJ. Bruce Fields 33238a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 332406b332a5SJ. Bruce Fields return nfserr_toosmall; 33258a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 332606b332a5SJ. Bruce Fields return nfserr_toosmall; 332706b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 332806b332a5SJ. Bruce Fields if (ca->maxops < 2) 332906b332a5SJ. Bruce Fields return nfserr_toosmall; 333006b332a5SJ. Bruce Fields 333106b332a5SJ. Bruce Fields return nfs_ok; 3332069b6ad4SAndy Adamson } 3333069b6ad4SAndy Adamson 3334b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 3335b78724b7SJ. Bruce Fields { 3336b78724b7SJ. Bruce Fields switch (cbs->flavor) { 3337b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 3338b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 3339b78724b7SJ. Bruce Fields return nfs_ok; 3340b78724b7SJ. Bruce Fields default: 3341b78724b7SJ. Bruce Fields /* 3342b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 3343b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 3344b78724b7SJ. Bruce Fields * GSS. 3345b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 3346b78724b7SJ. Bruce Fields * client might think it can already handle: 3347b78724b7SJ. Bruce Fields */ 3348b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 3349b78724b7SJ. Bruce Fields } 3350b78724b7SJ. Bruce Fields } 3351b78724b7SJ. Bruce Fields 3352069b6ad4SAndy Adamson __be32 3353069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 3354eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 3355069b6ad4SAndy Adamson { 3356eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 3357363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 3358ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 3359d20c11d8SJeff Layton struct nfs4_client *old = NULL; 3360ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 336181f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 336249557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 336357b7b43bSJ. Bruce Fields __be32 status = 0; 33648daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3365ec6b5d7bSAndy Adamson 3366a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 3367a62573dcSMi Jinlong return nfserr_inval; 3368b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 3369b78724b7SJ. Bruce Fields if (status) 3370b78724b7SJ. Bruce Fields return status; 337155c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 3372373cd409SJ. Bruce Fields if (status) 3373373cd409SJ. Bruce Fields return status; 337406b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 337506b332a5SJ. Bruce Fields if (status) 3376f403e450SKinglong Mee goto out_release_drc_mem; 337781f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 337860810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 337955c760cfSJ. Bruce Fields if (!new) 338055c760cfSJ. Bruce Fields goto out_release_drc_mem; 338181f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 338281f0b2a4SJ. Bruce Fields if (!conn) 338381f0b2a4SJ. Bruce Fields goto out_free_session; 3384a62573dcSMi Jinlong 3385d20c11d8SJeff Layton spin_lock(&nn->client_lock); 33860a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 33878daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 338878389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3389ec6b5d7bSAndy Adamson 3390ec6b5d7bSAndy Adamson if (conf) { 339157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3392dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 339357266a6eSJ. Bruce Fields goto out_free_conn; 339449557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 339549557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 3396f5e22bb6SKinglong Mee if (status) { 3397f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 339849557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 339981f0b2a4SJ. Bruce Fields goto out_free_conn; 3400ec6b5d7bSAndy Adamson } 3401ec6b5d7bSAndy Adamson } else if (unconf) { 3402ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 3403363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 3404ec6b5d7bSAndy Adamson status = nfserr_clid_inuse; 340581f0b2a4SJ. Bruce Fields goto out_free_conn; 3406ec6b5d7bSAndy Adamson } 340757266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3408dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 340957266a6eSJ. Bruce Fields goto out_free_conn; 341049557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 341149557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 341238eb76a5SAndy Adamson if (status) { 341338eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 3414ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 341581f0b2a4SJ. Bruce Fields goto out_free_conn; 3416ec6b5d7bSAndy Adamson } 3417382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3418221a6876SJ. Bruce Fields if (old) { 3419d20c11d8SJeff Layton status = mark_client_expired_locked(old); 34207abea1e8SJeff Layton if (status) { 34217abea1e8SJeff Layton old = NULL; 3422221a6876SJ. Bruce Fields goto out_free_conn; 3423221a6876SJ. Bruce Fields } 34247abea1e8SJeff Layton } 34258f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 3426ec6b5d7bSAndy Adamson conf = unconf; 3427ec6b5d7bSAndy Adamson } else { 3428ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 342981f0b2a4SJ. Bruce Fields goto out_free_conn; 3430ec6b5d7bSAndy Adamson } 343181f0b2a4SJ. Bruce Fields status = nfs_ok; 34324ce85c8cSChuck Lever /* Persistent sessions are not supported */ 3433408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 34344ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 3435408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 3436408b79bcSJ. Bruce Fields 343781f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 3438d20c11d8SJeff Layton nfsd4_get_session_locked(new); 343981f0b2a4SJ. Bruce Fields 3440ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 3441ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 344286c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 344349557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 3444ec6b5d7bSAndy Adamson 3445d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 344649557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 3447d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3448d20c11d8SJeff Layton /* init connection and backchannel */ 3449d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 3450d20c11d8SJeff Layton nfsd4_put_session(new); 3451d20c11d8SJeff Layton if (old) 3452d20c11d8SJeff Layton expire_client(old); 3453ec6b5d7bSAndy Adamson return status; 345481f0b2a4SJ. Bruce Fields out_free_conn: 3455d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 345681f0b2a4SJ. Bruce Fields free_conn(conn); 3457d20c11d8SJeff Layton if (old) 3458d20c11d8SJeff Layton expire_client(old); 345981f0b2a4SJ. Bruce Fields out_free_session: 346081f0b2a4SJ. Bruce Fields __free_session(new); 346155c760cfSJ. Bruce Fields out_release_drc_mem: 346255c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 34631ca50792SJ. Bruce Fields return status; 3464069b6ad4SAndy Adamson } 3465069b6ad4SAndy Adamson 34661d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 34671d1bc8f2SJ. Bruce Fields { 34681d1bc8f2SJ. Bruce Fields switch (*dir) { 34691d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 34701d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 34711d1bc8f2SJ. Bruce Fields return nfs_ok; 34721d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 34731d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 34741d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 34751d1bc8f2SJ. Bruce Fields return nfs_ok; 3476fc5fc5d7Szhengbin } 34771d1bc8f2SJ. Bruce Fields return nfserr_inval; 34781d1bc8f2SJ. Bruce Fields } 34791d1bc8f2SJ. Bruce Fields 3480eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 3481eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3482eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3483cb73a9f4SJ. Bruce Fields { 3484eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 3485cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 3486c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3487b78724b7SJ. Bruce Fields __be32 status; 3488cb73a9f4SJ. Bruce Fields 3489b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 3490b78724b7SJ. Bruce Fields if (status) 3491b78724b7SJ. Bruce Fields return status; 3492c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3493cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 3494cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 3495c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3496cb73a9f4SJ. Bruce Fields 3497cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 3498cb73a9f4SJ. Bruce Fields 3499cb73a9f4SJ. Bruce Fields return nfs_ok; 3500cb73a9f4SJ. Bruce Fields } 3501cb73a9f4SJ. Bruce Fields 3502c2d715a1SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3503c2d715a1SJ. Bruce Fields { 3504c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3505c2d715a1SJ. Bruce Fields 3506c2d715a1SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3507c2d715a1SJ. Bruce Fields if (c->cn_xprt == xpt) { 3508c2d715a1SJ. Bruce Fields return c; 3509c2d715a1SJ. Bruce Fields } 3510c2d715a1SJ. Bruce Fields } 3511c2d715a1SJ. Bruce Fields return NULL; 3512c2d715a1SJ. Bruce Fields } 3513c2d715a1SJ. Bruce Fields 3514c2d715a1SJ. Bruce Fields static __be32 nfsd4_match_existing_connection(struct svc_rqst *rqst, 3515c2d715a1SJ. Bruce Fields struct nfsd4_session *session, u32 req) 3516c2d715a1SJ. Bruce Fields { 3517c2d715a1SJ. Bruce Fields struct nfs4_client *clp = session->se_client; 3518c2d715a1SJ. Bruce Fields struct svc_xprt *xpt = rqst->rq_xprt; 3519c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3520c2d715a1SJ. Bruce Fields __be32 status; 3521c2d715a1SJ. Bruce Fields 3522c2d715a1SJ. Bruce Fields /* Following the last paragraph of RFC 5661 Section 18.34.3: */ 3523c2d715a1SJ. Bruce Fields spin_lock(&clp->cl_lock); 3524c2d715a1SJ. Bruce Fields c = __nfsd4_find_conn(xpt, session); 3525c2d715a1SJ. Bruce Fields if (!c) 3526c2d715a1SJ. Bruce Fields status = nfserr_noent; 3527c2d715a1SJ. Bruce Fields else if (req == c->cn_flags) 3528c2d715a1SJ. Bruce Fields status = nfs_ok; 3529c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_FORE_OR_BOTH && 3530c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_BACK) 3531c2d715a1SJ. Bruce Fields status = nfs_ok; 3532c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_BACK_OR_BOTH && 3533c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_FORE) 3534c2d715a1SJ. Bruce Fields status = nfs_ok; 3535c2d715a1SJ. Bruce Fields else 3536c2d715a1SJ. Bruce Fields status = nfserr_inval; 3537c2d715a1SJ. Bruce Fields spin_unlock(&clp->cl_lock); 3538c2d715a1SJ. Bruce Fields return status; 3539c2d715a1SJ. Bruce Fields } 3540c2d715a1SJ. Bruce Fields 35411d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 35421d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 3543eb69853dSChristoph Hellwig union nfsd4_op_u *u) 35441d1bc8f2SJ. Bruce Fields { 3545eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 35461d1bc8f2SJ. Bruce Fields __be32 status; 35473ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 35484f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 3549d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3550d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 35511d1bc8f2SJ. Bruce Fields 35521d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 35531d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 3554c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3555d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 3556c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 35574f6e6c17SJ. Bruce Fields if (!session) 3558d4e19e70STrond Myklebust goto out_no_session; 355957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3560dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 356157266a6eSJ. Bruce Fields goto out; 3562c2d715a1SJ. Bruce Fields status = nfsd4_match_existing_connection(rqstp, session, bcts->dir); 3563c2d715a1SJ. Bruce Fields if (status == nfs_ok || status == nfserr_inval) 3564c2d715a1SJ. Bruce Fields goto out; 35651d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 35663ba63671SJ. Bruce Fields if (status) 35674f6e6c17SJ. Bruce Fields goto out; 35683ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 35694f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 35703ba63671SJ. Bruce Fields if (!conn) 35714f6e6c17SJ. Bruce Fields goto out; 35724f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 35734f6e6c17SJ. Bruce Fields status = nfs_ok; 35744f6e6c17SJ. Bruce Fields out: 3575d4e19e70STrond Myklebust nfsd4_put_session(session); 3576d4e19e70STrond Myklebust out_no_session: 35774f6e6c17SJ. Bruce Fields return status; 35781d1bc8f2SJ. Bruce Fields } 35791d1bc8f2SJ. Bruce Fields 3580665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 35815d4cec2fSJ. Bruce Fields { 3582665d5072SJ. Bruce Fields if (!cstate->session) 358351d87bc2SFengguang Wu return false; 3584665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 35855d4cec2fSJ. Bruce Fields } 35865d4cec2fSJ. Bruce Fields 3587069b6ad4SAndy Adamson __be32 3588eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 3589eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3590069b6ad4SAndy Adamson { 3591ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 3592e10e0cfcSBenny Halevy struct nfsd4_session *ses; 3593abcdff09SJ. Bruce Fields __be32 status; 3594f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 3595d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 3596d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3597e10e0cfcSBenny Halevy 3598abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 3599ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 360057716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 3601abcdff09SJ. Bruce Fields goto out; 3602f0f51f5cSJ. Bruce Fields ref_held_by_me++; 360357716355SJ. Bruce Fields } 3604ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 3605c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3606ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 3607abcdff09SJ. Bruce Fields if (!ses) 3608abcdff09SJ. Bruce Fields goto out_client_lock; 360957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3610dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 3611d4e19e70STrond Myklebust goto out_put_session; 3612f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 361366b2b9b2SJ. Bruce Fields if (status) 3614f0f51f5cSJ. Bruce Fields goto out_put_session; 3615e10e0cfcSBenny Halevy unhash_session(ses); 3616c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3617e10e0cfcSBenny Halevy 361884f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 361919cf5c02SJ. Bruce Fields 3620c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3621e10e0cfcSBenny Halevy status = nfs_ok; 3622f0f51f5cSJ. Bruce Fields out_put_session: 3623d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3624abcdff09SJ. Bruce Fields out_client_lock: 3625abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3626e10e0cfcSBenny Halevy out: 3627e10e0cfcSBenny Halevy return status; 3628069b6ad4SAndy Adamson } 3629069b6ad4SAndy Adamson 363057266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3631328ead28SJ. Bruce Fields { 3632328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3633a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 363457266a6eSJ. Bruce Fields __be32 status = nfs_ok; 363521b75b01SJ. Bruce Fields int ret; 3636328ead28SJ. Bruce Fields 3637328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3638a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 363957266a6eSJ. Bruce Fields if (c) 364057266a6eSJ. Bruce Fields goto out_free; 364157266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 364257266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 364357266a6eSJ. Bruce Fields goto out_free; 3644328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3645328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 364621b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 364721b75b01SJ. Bruce Fields if (ret) 364821b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 364921b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 365057266a6eSJ. Bruce Fields return nfs_ok; 365157266a6eSJ. Bruce Fields out_free: 365257266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 365357266a6eSJ. Bruce Fields free_conn(new); 365457266a6eSJ. Bruce Fields return status; 3655328ead28SJ. Bruce Fields } 3656328ead28SJ. Bruce Fields 3657868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3658868b89c3SMi Jinlong { 3659868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3660868b89c3SMi Jinlong 3661868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3662868b89c3SMi Jinlong } 3663868b89c3SMi Jinlong 3664ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3665ae82a8d0SMi Jinlong struct nfsd4_session *session) 3666ae82a8d0SMi Jinlong { 3667ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3668ae82a8d0SMi Jinlong 3669ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3670ae82a8d0SMi Jinlong } 3671ae82a8d0SMi Jinlong 367253da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 367353da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 367453da6a53SJ. Bruce Fields { 367553da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 367653da6a53SJ. Bruce Fields 367753da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 367853da6a53SJ. Bruce Fields (bool)seq->cachethis) 367953da6a53SJ. Bruce Fields return false; 368053da6a53SJ. Bruce Fields /* 36816e73e92bSScott Mayhew * If there's an error then the reply can have fewer ops than 36826e73e92bSScott Mayhew * the call. 368353da6a53SJ. Bruce Fields */ 36846e73e92bSScott Mayhew if (slot->sl_opcnt < argp->opcnt && !slot->sl_status) 36856e73e92bSScott Mayhew return false; 36866e73e92bSScott Mayhew /* 36876e73e92bSScott Mayhew * But if we cached a reply with *more* ops than the call you're 36886e73e92bSScott Mayhew * sending us now, then this new call is clearly not really a 36896e73e92bSScott Mayhew * replay of the old one: 36906e73e92bSScott Mayhew */ 36916e73e92bSScott Mayhew if (slot->sl_opcnt > argp->opcnt) 369253da6a53SJ. Bruce Fields return false; 369353da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 369453da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 369553da6a53SJ. Bruce Fields return false; 369653da6a53SJ. Bruce Fields /* 369753da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 369853da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 369953da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 370053da6a53SJ. Bruce Fields * the reply), so we don't bother. 370153da6a53SJ. Bruce Fields */ 370253da6a53SJ. Bruce Fields return true; 370353da6a53SJ. Bruce Fields } 370453da6a53SJ. Bruce Fields 3705069b6ad4SAndy Adamson __be32 3706eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3707eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3708069b6ad4SAndy Adamson { 3709eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3710f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 371147ee5298SJ. Bruce Fields struct xdr_stream *xdr = &resp->xdr; 3712b85d4c01SBenny Halevy struct nfsd4_session *session; 3713221a6876SJ. Bruce Fields struct nfs4_client *clp; 3714b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3715a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 371657b7b43bSJ. Bruce Fields __be32 status; 371747ee5298SJ. Bruce Fields int buflen; 3718d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3719d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3720b85d4c01SBenny Halevy 3721f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3722f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3723f9bb94c4SAndy Adamson 3724a663bdd8SJ. Bruce Fields /* 3725a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3726a663bdd8SJ. Bruce Fields * below. 3727a663bdd8SJ. Bruce Fields */ 3728a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3729a663bdd8SJ. Bruce Fields if (!conn) 3730a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3731a663bdd8SJ. Bruce Fields 3732c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3733d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3734b85d4c01SBenny Halevy if (!session) 3735221a6876SJ. Bruce Fields goto out_no_session; 3736221a6876SJ. Bruce Fields clp = session->se_client; 3737b85d4c01SBenny Halevy 3738868b89c3SMi Jinlong status = nfserr_too_many_ops; 3739868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 374066b2b9b2SJ. Bruce Fields goto out_put_session; 3741868b89c3SMi Jinlong 3742ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3743ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 374466b2b9b2SJ. Bruce Fields goto out_put_session; 3745ae82a8d0SMi Jinlong 3746b85d4c01SBenny Halevy status = nfserr_badslot; 37476c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 374866b2b9b2SJ. Bruce Fields goto out_put_session; 3749b85d4c01SBenny Halevy 3750557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3751b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3752b85d4c01SBenny Halevy 3753a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3754a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3755a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3756a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 3757a8dfdaebSAndy Adamson 375873e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 375973e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 3760b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 3761bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 3762bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 376366b2b9b2SJ. Bruce Fields goto out_put_session; 376453da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 376553da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 376653da6a53SJ. Bruce Fields goto out_put_session; 3767b85d4c01SBenny Halevy cstate->slot = slot; 3768b85d4c01SBenny Halevy cstate->session = session; 37694b24ca7dSJeff Layton cstate->clp = clp; 3770da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 3771557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 3772bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 3773da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 3774aaf84eb9SBenny Halevy goto out; 3775b85d4c01SBenny Halevy } 3776b85d4c01SBenny Halevy if (status) 377766b2b9b2SJ. Bruce Fields goto out_put_session; 3778b85d4c01SBenny Halevy 377957266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 3780a663bdd8SJ. Bruce Fields conn = NULL; 378157266a6eSJ. Bruce Fields if (status) 378257266a6eSJ. Bruce Fields goto out_put_session; 3783328ead28SJ. Bruce Fields 378447ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 378547ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 378647ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 378747ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 378847ee5298SJ. Bruce Fields nfserr_rep_too_big; 3789a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 379047ee5298SJ. Bruce Fields goto out_put_session; 379132aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 379247ee5298SJ. Bruce Fields 379347ee5298SJ. Bruce Fields status = nfs_ok; 3794b85d4c01SBenny Halevy /* Success! bump slot seqid */ 3795b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 3796bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 379773e79482SJ. Bruce Fields if (seq->cachethis) 379873e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 3799bf5c43c8SJ. Bruce Fields else 3800bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 3801b85d4c01SBenny Halevy 3802b85d4c01SBenny Halevy cstate->slot = slot; 3803b85d4c01SBenny Halevy cstate->session = session; 38044b24ca7dSJeff Layton cstate->clp = clp; 3805b85d4c01SBenny Halevy 3806b85d4c01SBenny Halevy out: 38075423732aSBenny Halevy switch (clp->cl_cb_state) { 38085423732aSBenny Halevy case NFSD4_CB_DOWN: 3809fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 38105423732aSBenny Halevy break; 38115423732aSBenny Halevy case NFSD4_CB_FAULT: 3812fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 38135423732aSBenny Halevy break; 3814fc0c3dd1SBenny Halevy default: 3815fc0c3dd1SBenny Halevy seq->status_flags = 0; 38165423732aSBenny Halevy } 38173bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 38183bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 3819221a6876SJ. Bruce Fields out_no_session: 38203f42d2c4SKinglong Mee if (conn) 38213f42d2c4SKinglong Mee free_conn(conn); 3822c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3823b85d4c01SBenny Halevy return status; 382466b2b9b2SJ. Bruce Fields out_put_session: 3825d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 3826221a6876SJ. Bruce Fields goto out_no_session; 3827069b6ad4SAndy Adamson } 3828069b6ad4SAndy Adamson 3829b607664eSTrond Myklebust void 3830b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 3831b607664eSTrond Myklebust { 3832b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 3833b607664eSTrond Myklebust 3834b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 3835b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 3836b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 3837b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3838b607664eSTrond Myklebust } 3839d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 3840b607664eSTrond Myklebust nfsd4_put_session(cs->session); 38414b24ca7dSJeff Layton } else if (cs->clp) 38424b24ca7dSJeff Layton put_client_renew(cs->clp); 3843b607664eSTrond Myklebust } 3844b607664eSTrond Myklebust 3845345c2842SMi Jinlong __be32 3846eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 3847eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3848eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3849345c2842SMi Jinlong { 3850eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 38516b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 38526b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 385357b7b43bSJ. Bruce Fields __be32 status = 0; 38548daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3855345c2842SMi Jinlong 38566b10ad19STrond Myklebust spin_lock(&nn->client_lock); 38570a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 38588daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 385978389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3860345c2842SMi Jinlong 3861345c2842SMi Jinlong if (conf) { 3862c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 3863345c2842SMi Jinlong status = nfserr_clientid_busy; 3864345c2842SMi Jinlong goto out; 3865345c2842SMi Jinlong } 3866fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3867fd699b8aSJeff Layton if (status) 3868fd699b8aSJeff Layton goto out; 38696b10ad19STrond Myklebust clp = conf; 3870345c2842SMi Jinlong } else if (unconf) 3871345c2842SMi Jinlong clp = unconf; 3872345c2842SMi Jinlong else { 3873345c2842SMi Jinlong status = nfserr_stale_clientid; 3874345c2842SMi Jinlong goto out; 3875345c2842SMi Jinlong } 3876dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 38776b10ad19STrond Myklebust clp = NULL; 387857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 387957266a6eSJ. Bruce Fields goto out; 388057266a6eSJ. Bruce Fields } 38816b10ad19STrond Myklebust unhash_client_locked(clp); 3882345c2842SMi Jinlong out: 38836b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 38846b10ad19STrond Myklebust if (clp) 38856b10ad19STrond Myklebust expire_client(clp); 3886345c2842SMi Jinlong return status; 3887345c2842SMi Jinlong } 3888345c2842SMi Jinlong 3889069b6ad4SAndy Adamson __be32 3890eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 3891eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 38924dc6ec00SJ. Bruce Fields { 3893eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 389457b7b43bSJ. Bruce Fields __be32 status = 0; 3895bcecf1ccSMi Jinlong 38964dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 38974dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 38984dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 38994dc6ec00SJ. Bruce Fields /* 39004dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 39014dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 39024dc6ec00SJ. Bruce Fields */ 39034dc6ec00SJ. Bruce Fields return nfs_ok; 39044dc6ec00SJ. Bruce Fields } 3905bcecf1ccSMi Jinlong 3906bcecf1ccSMi Jinlong status = nfserr_complete_already; 3907a52d726bSJeff Layton if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, 3908a52d726bSJeff Layton &cstate->session->se_client->cl_flags)) 3909bcecf1ccSMi Jinlong goto out; 3910bcecf1ccSMi Jinlong 3911bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 3912bcecf1ccSMi Jinlong if (is_client_expired(cstate->session->se_client)) 39134dc6ec00SJ. Bruce Fields /* 39144dc6ec00SJ. Bruce Fields * The following error isn't really legal. 39154dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 39164dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 39174dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 39184dc6ec00SJ. Bruce Fields * client. 39194dc6ec00SJ. Bruce Fields */ 3920bcecf1ccSMi Jinlong goto out; 3921bcecf1ccSMi Jinlong 3922bcecf1ccSMi Jinlong status = nfs_ok; 39232a4317c5SJeff Layton nfsd4_client_record_create(cstate->session->se_client); 3924362063a5SScott Mayhew inc_reclaim_complete(cstate->session->se_client); 3925bcecf1ccSMi Jinlong out: 3926bcecf1ccSMi Jinlong return status; 39274dc6ec00SJ. Bruce Fields } 39284dc6ec00SJ. Bruce Fields 39294dc6ec00SJ. Bruce Fields __be32 3930b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3931eb69853dSChristoph Hellwig union nfsd4_op_u *u) 39321da177e4SLinus Torvalds { 3933eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 3934a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 39351da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 39363dbacee6STrond Myklebust struct nfs4_client *conf, *new; 39373dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 3938b37ad28bSAl Viro __be32 status; 3939c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3940a55370a3SNeilBrown 39415cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 39425cc40fd7STrond Myklebust if (new == NULL) 39435cc40fd7STrond Myklebust return nfserr_jukebox; 394463db4632SJ. Bruce Fields /* Cases below refer to rfc 3530 section 14.2.33: */ 39453dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3946382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 39472b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 394863db4632SJ. Bruce Fields /* case 0: */ 39491da177e4SLinus Torvalds status = nfserr_clid_inuse; 3950e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 3951e203d506SJ. Bruce Fields goto out; 3952026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 3953dd5e3fbcSChuck Lever trace_nfsd_clid_inuse_err(conf); 39541da177e4SLinus Torvalds goto out; 39551da177e4SLinus Torvalds } 39561da177e4SLinus Torvalds } 3957a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 39581da177e4SLinus Torvalds if (unconf) 39593dbacee6STrond Myklebust unhash_client_locked(unconf); 396045f56da8SChuck Lever /* We need to handle only case 1: probable callback update */ 396141eb1670SKinglong Mee if (conf && same_verf(&conf->cl_verifier, &clverifier)) { 39621da177e4SLinus Torvalds copy_clid(new, conf); 396341eb1670SKinglong Mee gen_confirm(new, nn); 396445f56da8SChuck Lever } 39658323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 39666f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 3967ac55fdc4SJeff Layton add_to_unconfirmed(new); 39681da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 39691da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 39701da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 39715cc40fd7STrond Myklebust new = NULL; 39721da177e4SLinus Torvalds status = nfs_ok; 39731da177e4SLinus Torvalds out: 39743dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 39755cc40fd7STrond Myklebust if (new) 39765cc40fd7STrond Myklebust free_client(new); 39773dbacee6STrond Myklebust if (unconf) 39783dbacee6STrond Myklebust expire_client(unconf); 39791da177e4SLinus Torvalds return status; 39801da177e4SLinus Torvalds } 39811da177e4SLinus Torvalds 39821da177e4SLinus Torvalds 3983b37ad28bSAl Viro __be32 3984b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 3985b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 3986eb69853dSChristoph Hellwig union nfsd4_op_u *u) 39871da177e4SLinus Torvalds { 3988eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 3989eb69853dSChristoph Hellwig &u->setclientid_confirm; 399021ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 3991d20c11d8SJeff Layton struct nfs4_client *old = NULL; 39921da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 39931da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 3994b37ad28bSAl Viro __be32 status; 39957f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 39961da177e4SLinus Torvalds 39972c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 39981da177e4SLinus Torvalds return nfserr_stale_clientid; 399921ab45a4SNeilBrown 4000d20c11d8SJeff Layton spin_lock(&nn->client_lock); 40018daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 40020a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 4003a186e767SJ. Bruce Fields /* 40048695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 40058695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 4006f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 4007f984a7ceSJ. Bruce Fields * 4008f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 4009a186e767SJ. Bruce Fields */ 4010f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 40118695b90aSJ. Bruce Fields if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) 40128695b90aSJ. Bruce Fields goto out; 40138695b90aSJ. Bruce Fields if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) 40148695b90aSJ. Bruce Fields goto out; 401563db4632SJ. Bruce Fields /* cases below refer to rfc 3530 section 14.2.34: */ 401690d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 40177d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 40187d22fc11SJ. Bruce Fields /* case 2: probable retransmit */ 401990d700b7SJ. Bruce Fields status = nfs_ok; 40207d22fc11SJ. Bruce Fields } else /* case 4: client hasn't noticed we rebooted yet? */ 402190d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 402290d700b7SJ. Bruce Fields goto out; 402390d700b7SJ. Bruce Fields } 402490d700b7SJ. Bruce Fields status = nfs_ok; 402590d700b7SJ. Bruce Fields if (conf) { /* case 1: callback update */ 4026d20c11d8SJeff Layton old = unconf; 4027d20c11d8SJeff Layton unhash_client_locked(old); 40285a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 402990d700b7SJ. Bruce Fields } else { /* case 3: normal case; new or rebooted client */ 4030d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 4031d20c11d8SJeff Layton if (old) { 40322b634821SJ. Bruce Fields status = nfserr_clid_inuse; 40332b634821SJ. Bruce Fields if (client_has_state(old) 40342b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 40352b634821SJ. Bruce Fields &old->cl_cred)) 40362b634821SJ. Bruce Fields goto out; 4037d20c11d8SJeff Layton status = mark_client_expired_locked(old); 40387abea1e8SJeff Layton if (status) { 40397abea1e8SJeff Layton old = NULL; 4040221a6876SJ. Bruce Fields goto out; 4041221a6876SJ. Bruce Fields } 40427abea1e8SJeff Layton } 40431da177e4SLinus Torvalds move_to_confirmed(unconf); 4044d20c11d8SJeff Layton conf = unconf; 404508e8987cSNeilBrown } 4046d20c11d8SJeff Layton get_client_locked(conf); 4047d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4048d20c11d8SJeff Layton nfsd4_probe_callback(conf); 4049d20c11d8SJeff Layton spin_lock(&nn->client_lock); 4050d20c11d8SJeff Layton put_client_renew_locked(conf); 40511da177e4SLinus Torvalds out: 4052d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4053d20c11d8SJeff Layton if (old) 4054d20c11d8SJeff Layton expire_client(old); 40551da177e4SLinus Torvalds return status; 40561da177e4SLinus Torvalds } 40571da177e4SLinus Torvalds 405832513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 40591da177e4SLinus Torvalds { 406032513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 406132513b40SJ. Bruce Fields } 406232513b40SJ. Bruce Fields 406332513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 40645b095e99SJeff Layton static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, 40655b095e99SJeff Layton struct nfs4_file *fp) 406632513b40SJ. Bruce Fields { 4067950e0118STrond Myklebust lockdep_assert_held(&state_lock); 4068950e0118STrond Myklebust 4069818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 40701d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 40718beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 40728beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 40738287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 4074e2cf80d7STrond Myklebust fh_copy_shallow(&fp->fi_fhandle, fh); 40750c637be8SJeff Layton fp->fi_deleg_file = NULL; 407647f9940cSMeelap Shah fp->fi_had_conflict = false; 4077baeb4ff0SJeff Layton fp->fi_share_deny = 0; 4078f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 4079f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 40809cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 40819cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 4082c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 40839cf514ccSChristoph Hellwig #endif 40845b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 40851da177e4SLinus Torvalds } 40861da177e4SLinus Torvalds 4087e8ff2a84SJ. Bruce Fields void 4088e60d4398SNeilBrown nfsd4_free_slabs(void) 4089e60d4398SNeilBrown { 40909258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4091abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 4092abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4093abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4094abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4095abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 40969258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 4097e60d4398SNeilBrown } 40981da177e4SLinus Torvalds 409972083396SBryan Schumaker int 41001da177e4SLinus Torvalds nfsd4_init_slabs(void) 41011da177e4SLinus Torvalds { 41029258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 41039258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 41049258a2d5SJeff Layton if (client_slab == NULL) 41059258a2d5SJeff Layton goto out; 4106fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 4107fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 4108fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 41099258a2d5SJeff Layton goto out_free_client_slab; 4110fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 41113c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 4112fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 4113abf1135bSChristoph Hellwig goto out_free_openowner_slab; 4114e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 411520c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 4116e60d4398SNeilBrown if (file_slab == NULL) 4117abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 41185ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 4119dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 41205ac049acSNeilBrown if (stateid_slab == NULL) 4121abf1135bSChristoph Hellwig goto out_free_file_slab; 41225b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 412320c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 41245b2d21c1SNeilBrown if (deleg_slab == NULL) 4125abf1135bSChristoph Hellwig goto out_free_stateid_slab; 41268287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 41278287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 41288287f009SSachin Bhamare if (odstate_slab == NULL) 41298287f009SSachin Bhamare goto out_free_deleg_slab; 4130e60d4398SNeilBrown return 0; 4131abf1135bSChristoph Hellwig 41328287f009SSachin Bhamare out_free_deleg_slab: 41338287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 4134abf1135bSChristoph Hellwig out_free_stateid_slab: 4135abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4136abf1135bSChristoph Hellwig out_free_file_slab: 4137abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4138abf1135bSChristoph Hellwig out_free_lockowner_slab: 4139abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4140abf1135bSChristoph Hellwig out_free_openowner_slab: 4141abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 41429258a2d5SJeff Layton out_free_client_slab: 41439258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4144abf1135bSChristoph Hellwig out: 41451da177e4SLinus Torvalds return -ENOMEM; 41461da177e4SLinus Torvalds } 41471da177e4SLinus Torvalds 4148ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 4149ff194bd9SJ. Bruce Fields { 4150ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 4151ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 4152ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 415358fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 415458fb12e6SJeff Layton } 415558fb12e6SJeff Layton 415658fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 415758fb12e6SJeff Layton struct nfs4_stateowner *so) 415858fb12e6SJeff Layton { 415958fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 416058fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 4161b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 416258fb12e6SJeff Layton } 416358fb12e6SJeff Layton } 416458fb12e6SJeff Layton 416558fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 416658fb12e6SJeff Layton { 416758fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 416858fb12e6SJeff Layton 416958fb12e6SJeff Layton if (so != NULL) { 417058fb12e6SJeff Layton cstate->replay_owner = NULL; 417158fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 417258fb12e6SJeff Layton nfs4_put_stateowner(so); 417358fb12e6SJeff Layton } 4174ff194bd9SJ. Bruce Fields } 4175ff194bd9SJ. Bruce Fields 4176fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 41771da177e4SLinus Torvalds { 41781da177e4SLinus Torvalds struct nfs4_stateowner *sop; 41791da177e4SLinus Torvalds 4180fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 4181ff194bd9SJ. Bruce Fields if (!sop) 4182ff194bd9SJ. Bruce Fields return NULL; 4183ff194bd9SJ. Bruce Fields 41846f4859b8SJ. Bruce Fields xdr_netobj_dup(&sop->so_owner, owner, GFP_KERNEL); 4185ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 4186fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 4187ff194bd9SJ. Bruce Fields return NULL; 4188ff194bd9SJ. Bruce Fields } 4189ff194bd9SJ. Bruce Fields 4190ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 4191ff194bd9SJ. Bruce Fields sop->so_client = clp; 4192ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 41936b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 41941da177e4SLinus Torvalds return sop; 41951da177e4SLinus Torvalds } 4196ff194bd9SJ. Bruce Fields 4197fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 4198ff194bd9SJ. Bruce Fields { 4199d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 42009b531137SStanislav Kinsbursky 4201d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 4202d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 4203fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 42041da177e4SLinus Torvalds } 42051da177e4SLinus Torvalds 42068f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 42078f4b54c5SJeff Layton { 4208d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 42098f4b54c5SJeff Layton } 42108f4b54c5SJeff Layton 42116b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 42126b180f0bSJeff Layton { 42136b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 42146b180f0bSJeff Layton 42156b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 42166b180f0bSJeff Layton } 42176b180f0bSJeff Layton 42186b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 42198f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 42206b180f0bSJeff Layton .so_free = nfs4_free_openowner, 42216b180f0bSJeff Layton }; 42226b180f0bSJeff Layton 42237fc0564eSAndrew Elble static struct nfs4_ol_stateid * 42247fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 42257fc0564eSAndrew Elble { 42267fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 42277fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 42287fc0564eSAndrew Elble 42297fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 42307fc0564eSAndrew Elble 42317fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 42327fc0564eSAndrew Elble /* ignore lock owners */ 42337fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 42347fc0564eSAndrew Elble continue; 423515ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 423615ca08d3STrond Myklebust continue; 423715ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 42387fc0564eSAndrew Elble ret = local; 4239a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 42407fc0564eSAndrew Elble break; 42417fc0564eSAndrew Elble } 42427fc0564eSAndrew Elble } 42437fc0564eSAndrew Elble return ret; 42447fc0564eSAndrew Elble } 42457fc0564eSAndrew Elble 424615ca08d3STrond Myklebust static __be32 424715ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 424815ca08d3STrond Myklebust { 424915ca08d3STrond Myklebust __be32 ret = nfs_ok; 425015ca08d3STrond Myklebust 425115ca08d3STrond Myklebust switch (s->sc_type) { 425215ca08d3STrond Myklebust default: 425315ca08d3STrond Myklebust break; 42544f176417STrond Myklebust case 0: 425515ca08d3STrond Myklebust case NFS4_CLOSED_STID: 425615ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 425715ca08d3STrond Myklebust ret = nfserr_bad_stateid; 425815ca08d3STrond Myklebust break; 425915ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 426015ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 426115ca08d3STrond Myklebust } 426215ca08d3STrond Myklebust return ret; 426315ca08d3STrond Myklebust } 426415ca08d3STrond Myklebust 426515ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 426615ca08d3STrond Myklebust static __be32 426715ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 426815ca08d3STrond Myklebust { 426915ca08d3STrond Myklebust __be32 ret; 427015ca08d3STrond Myklebust 42714f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 427215ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 427315ca08d3STrond Myklebust if (ret != nfs_ok) 427415ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 427515ca08d3STrond Myklebust return ret; 427615ca08d3STrond Myklebust } 427715ca08d3STrond Myklebust 427815ca08d3STrond Myklebust static struct nfs4_ol_stateid * 427915ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 428015ca08d3STrond Myklebust { 428115ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 428215ca08d3STrond Myklebust for (;;) { 428315ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 428415ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 428515ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 428615ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 428715ca08d3STrond Myklebust break; 428815ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 428915ca08d3STrond Myklebust } 429015ca08d3STrond Myklebust return stp; 429115ca08d3STrond Myklebust } 429215ca08d3STrond Myklebust 4293fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 429413d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 4295db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 4296db24b3b4SJeff Layton { 429713d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 42987ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 42991da177e4SLinus Torvalds 4300fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 4301fe0750e5SJ. Bruce Fields if (!oo) 43021da177e4SLinus Torvalds return NULL; 43036b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 4304fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 4305fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 4306d3134b10SJeff Layton oo->oo_flags = 0; 4307db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 4308db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 4309fe0750e5SJ. Bruce Fields oo->oo_time = 0; 431038c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 4311fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 4312d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 4313d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 43147ffb5880STrond Myklebust if (ret == NULL) { 4315fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 43167ffb5880STrond Myklebust ret = oo; 43177ffb5880STrond Myklebust } else 4318d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 4319d50ffdedSKinglong Mee 4320d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 4321c5952338SJeff Layton return ret; 43221da177e4SLinus Torvalds } 43231da177e4SLinus Torvalds 43247fc0564eSAndrew Elble static struct nfs4_ol_stateid * 43258c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 43267fc0564eSAndrew Elble { 43271da177e4SLinus Torvalds 43287fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 43297fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 43308c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 43317fc0564eSAndrew Elble 43328c7245abSOleg Drokin stp = open->op_stp; 43335cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 43345cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 43354f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 43365cc1fb2aSOleg Drokin 433715ca08d3STrond Myklebust retry: 43387fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 43397fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 43407fc0564eSAndrew Elble 43417fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 43427fc0564eSAndrew Elble if (retstp) 43437fc0564eSAndrew Elble goto out_unlock; 43448c7245abSOleg Drokin 43458c7245abSOleg Drokin open->op_stp = NULL; 4346a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 43473abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 43483c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 4349b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 435013cd2184SNeilBrown get_nfs4_file(fp); 435111b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 43521da177e4SLinus Torvalds stp->st_access_bmap = 0; 43531da177e4SLinus Torvalds stp->st_deny_bmap = 0; 43544c4cd222SNeilBrown stp->st_openstp = NULL; 43551c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 43561d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 43577fc0564eSAndrew Elble 43587fc0564eSAndrew Elble out_unlock: 43591d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 43601c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 43615cc1fb2aSOleg Drokin if (retstp) { 436215ca08d3STrond Myklebust /* Handle races with CLOSE */ 436315ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 436415ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 436515ca08d3STrond Myklebust goto retry; 436615ca08d3STrond Myklebust } 43678c7245abSOleg Drokin /* To keep mutex tracking happy */ 43685cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 43698c7245abSOleg Drokin stp = retstp; 43705cc1fb2aSOleg Drokin } 43718c7245abSOleg Drokin return stp; 43721da177e4SLinus Torvalds } 43731da177e4SLinus Torvalds 4374d3134b10SJeff Layton /* 4375d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 4376d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 4377d3134b10SJeff Layton * them before returning however. 4378d3134b10SJeff Layton */ 43791da177e4SLinus Torvalds static void 4380d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 43811da177e4SLinus Torvalds { 4382217526e7SJeff Layton struct nfs4_ol_stateid *last; 4383d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 4384d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 4385d3134b10SJeff Layton nfsd_net_id); 438673758fedSStanislav Kinsbursky 4387fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 43881da177e4SLinus Torvalds 4389b401be22SJeff Layton /* 4390b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 4391b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 4392b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 4393b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 4394b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 4395b401be22SJeff Layton * there should be no danger of the refcount going back up again at 4396b401be22SJeff Layton * this point. 4397b401be22SJeff Layton */ 4398a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 4399b401be22SJeff Layton 4400d3134b10SJeff Layton release_all_access(s); 4401d3134b10SJeff Layton if (s->st_stid.sc_file) { 4402d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 4403d3134b10SJeff Layton s->st_stid.sc_file = NULL; 4404d3134b10SJeff Layton } 4405217526e7SJeff Layton 4406217526e7SJeff Layton spin_lock(&nn->client_lock); 4407217526e7SJeff Layton last = oo->oo_last_closed_stid; 4408d3134b10SJeff Layton oo->oo_last_closed_stid = s; 440973758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 441020b7d86fSArnd Bergmann oo->oo_time = ktime_get_boottime_seconds(); 4411217526e7SJeff Layton spin_unlock(&nn->client_lock); 4412217526e7SJeff Layton if (last) 4413217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 44141da177e4SLinus Torvalds } 44151da177e4SLinus Torvalds 44161da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 44171da177e4SLinus Torvalds static struct nfs4_file * 44185b095e99SJeff Layton find_file_locked(struct knfsd_fh *fh, unsigned int hashval) 44191da177e4SLinus Torvalds { 44201da177e4SLinus Torvalds struct nfs4_file *fp; 44211da177e4SLinus Torvalds 442236a80491SMadhuparna Bhowmik hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, 442336a80491SMadhuparna Bhowmik lockdep_is_held(&state_lock)) { 44244d94c2efSChristoph Hellwig if (fh_match(&fp->fi_fhandle, fh)) { 4425818a34ebSElena Reshetova if (refcount_inc_not_zero(&fp->fi_ref)) 44261da177e4SLinus Torvalds return fp; 44271da177e4SLinus Torvalds } 442813cd2184SNeilBrown } 44291da177e4SLinus Torvalds return NULL; 44301da177e4SLinus Torvalds } 44311da177e4SLinus Torvalds 4432e6ba76e1SChristoph Hellwig struct nfs4_file * 4433ca943217STrond Myklebust find_file(struct knfsd_fh *fh) 4434950e0118STrond Myklebust { 4435950e0118STrond Myklebust struct nfs4_file *fp; 44365b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 4437950e0118STrond Myklebust 44385b095e99SJeff Layton rcu_read_lock(); 44395b095e99SJeff Layton fp = find_file_locked(fh, hashval); 44405b095e99SJeff Layton rcu_read_unlock(); 4441950e0118STrond Myklebust return fp; 4442950e0118STrond Myklebust } 4443950e0118STrond Myklebust 4444950e0118STrond Myklebust static struct nfs4_file * 4445f9c00c3aSJeff Layton find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) 4446950e0118STrond Myklebust { 4447950e0118STrond Myklebust struct nfs4_file *fp; 44485b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 44495b095e99SJeff Layton 44505b095e99SJeff Layton rcu_read_lock(); 44515b095e99SJeff Layton fp = find_file_locked(fh, hashval); 44525b095e99SJeff Layton rcu_read_unlock(); 44535b095e99SJeff Layton if (fp) 44545b095e99SJeff Layton return fp; 4455950e0118STrond Myklebust 4456950e0118STrond Myklebust spin_lock(&state_lock); 44575b095e99SJeff Layton fp = find_file_locked(fh, hashval); 44585b095e99SJeff Layton if (likely(fp == NULL)) { 44595b095e99SJeff Layton nfsd4_init_file(fh, hashval, new); 4460950e0118STrond Myklebust fp = new; 4461950e0118STrond Myklebust } 4462950e0118STrond Myklebust spin_unlock(&state_lock); 4463950e0118STrond Myklebust 4464950e0118STrond Myklebust return fp; 4465950e0118STrond Myklebust } 4466950e0118STrond Myklebust 44674f83aa30SJ. Bruce Fields /* 44681da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 44691da177e4SLinus Torvalds * WRITE with all zero or all one stateid 44701da177e4SLinus Torvalds */ 4471b37ad28bSAl Viro static __be32 44721da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 44731da177e4SLinus Torvalds { 44741da177e4SLinus Torvalds struct nfs4_file *fp; 4475baeb4ff0SJeff Layton __be32 ret = nfs_ok; 44761da177e4SLinus Torvalds 4477ca943217STrond Myklebust fp = find_file(¤t_fh->fh_handle); 447813cd2184SNeilBrown if (!fp) 4479baeb4ff0SJeff Layton return ret; 4480baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 44811d31a253STrond Myklebust spin_lock(&fp->fi_lock); 4482baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 4483baeb4ff0SJeff Layton ret = nfserr_locked; 44841d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 448513cd2184SNeilBrown put_nfs4_file(fp); 448613cd2184SNeilBrown return ret; 44871da177e4SLinus Torvalds } 44881da177e4SLinus Torvalds 44890162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 44901da177e4SLinus Torvalds { 44910162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 449211b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 449311b9164aSTrond Myklebust nfsd_net_id); 4494e8c69d17SJ. Bruce Fields 449511b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 4496f54fe962SJeff Layton 449702e1215fSJeff Layton /* 449802e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 4499f54fe962SJeff Layton * already holding inode->i_lock. 4500f54fe962SJeff Layton * 4501dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 4502dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 4503dff1399fSJeff Layton */ 4504f54fe962SJeff Layton spin_lock(&state_lock); 4505dff1399fSJeff Layton if (dp->dl_time == 0) { 450620b7d86fSArnd Bergmann dp->dl_time = ktime_get_boottime_seconds(); 450702e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 450802e1215fSJeff Layton } 450902e1215fSJeff Layton spin_unlock(&state_lock); 4510dff1399fSJeff Layton } 45111da177e4SLinus Torvalds 45120162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 45130162ac2bSChristoph Hellwig struct rpc_task *task) 45140162ac2bSChristoph Hellwig { 45150162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 45160162ac2bSChristoph Hellwig 451712ed22f3SJ. Bruce Fields if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID || 451812ed22f3SJ. Bruce Fields dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4519a457974fSAndrew Elble return 1; 4520a457974fSAndrew Elble 45210162ac2bSChristoph Hellwig switch (task->tk_status) { 45220162ac2bSChristoph Hellwig case 0: 45230162ac2bSChristoph Hellwig return 1; 45241c73b9d2SScott Mayhew case -NFS4ERR_DELAY: 45251c73b9d2SScott Mayhew rpc_delay(task, 2 * HZ); 45261c73b9d2SScott Mayhew return 0; 45270162ac2bSChristoph Hellwig case -EBADHANDLE: 45280162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 45290162ac2bSChristoph Hellwig /* 45300162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 45310162ac2bSChristoph Hellwig * granting delegation. 45320162ac2bSChristoph Hellwig */ 45330162ac2bSChristoph Hellwig if (dp->dl_retries--) { 45340162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 45350162ac2bSChristoph Hellwig return 0; 45360162ac2bSChristoph Hellwig } 4537df561f66SGustavo A. R. Silva fallthrough; 45380162ac2bSChristoph Hellwig default: 45391c73b9d2SScott Mayhew return 1; 45400162ac2bSChristoph Hellwig } 45410162ac2bSChristoph Hellwig } 45420162ac2bSChristoph Hellwig 45430162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 45440162ac2bSChristoph Hellwig { 45450162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 45460162ac2bSChristoph Hellwig 45470162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 45480162ac2bSChristoph Hellwig } 45490162ac2bSChristoph Hellwig 4550c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 45510162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 45520162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 45530162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 45540162ac2bSChristoph Hellwig }; 45550162ac2bSChristoph Hellwig 455602e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 455702e1215fSJeff Layton { 455802e1215fSJeff Layton /* 455902e1215fSJeff Layton * We're assuming the state code never drops its reference 456002e1215fSJeff Layton * without first removing the lease. Since we're in this lease 45614a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 45624a269efbSJ. Bruce Fields * i_lock) we know the server hasn't removed the lease yet, and 45634a269efbSJ. Bruce Fields * we know it's safe to take a reference. 456402e1215fSJeff Layton */ 4565a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 4566f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 45676b57d9c8SJ. Bruce Fields } 45686b57d9c8SJ. Bruce Fields 45691c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 45704d01b7f5SJeff Layton static bool 45714d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 45726b57d9c8SJ. Bruce Fields { 45734d01b7f5SJeff Layton bool ret = false; 4574653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 4575653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 45766b57d9c8SJ. Bruce Fields 4577dd5e3fbcSChuck Lever trace_nfsd_deleg_break(&dp->dl_stid.sc_stateid); 4578dd5e3fbcSChuck Lever 45790272e1fdSJ. Bruce Fields /* 45800272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 4581acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 45826b57d9c8SJ. Bruce Fields * in time: 45830272e1fdSJ. Bruce Fields */ 45840272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 45851da177e4SLinus Torvalds 458602e1215fSJeff Layton spin_lock(&fp->fi_lock); 4587417c6629SJeff Layton fp->fi_had_conflict = true; 45885d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 458902e1215fSJeff Layton spin_unlock(&fp->fi_lock); 45904d01b7f5SJeff Layton return ret; 45911da177e4SLinus Torvalds } 45921da177e4SLinus Torvalds 459328df3d15SJ. Bruce Fields static bool nfsd_breaker_owns_lease(struct file_lock *fl) 459428df3d15SJ. Bruce Fields { 459528df3d15SJ. Bruce Fields struct nfs4_delegation *dl = fl->fl_owner; 459628df3d15SJ. Bruce Fields struct svc_rqst *rqst; 459728df3d15SJ. Bruce Fields struct nfs4_client *clp; 459828df3d15SJ. Bruce Fields 459928df3d15SJ. Bruce Fields if (!i_am_nfsd()) 460028df3d15SJ. Bruce Fields return NULL; 460128df3d15SJ. Bruce Fields rqst = kthread_data(current); 460213956160SJ. Bruce Fields /* Note rq_prog == NFS_ACL_PROGRAM is also possible: */ 460313956160SJ. Bruce Fields if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4) 460434b09af4SJ. Bruce Fields return NULL; 460528df3d15SJ. Bruce Fields clp = *(rqst->rq_lease_breaker); 460628df3d15SJ. Bruce Fields return dl->dl_stid.sc_client == clp; 460728df3d15SJ. Bruce Fields } 460828df3d15SJ. Bruce Fields 4609c45198edSJeff Layton static int 46107448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 46117448cc37SJeff Layton struct list_head *dispose) 46121da177e4SLinus Torvalds { 46131da177e4SLinus Torvalds if (arg & F_UNLCK) 4614c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 46151da177e4SLinus Torvalds else 46161da177e4SLinus Torvalds return -EAGAIN; 46171da177e4SLinus Torvalds } 46181da177e4SLinus Torvalds 46197b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 462028df3d15SJ. Bruce Fields .lm_breaker_owns_lease = nfsd_breaker_owns_lease, 46218fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 46228fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 46231da177e4SLinus Torvalds }; 46241da177e4SLinus Torvalds 46257a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 46267a8711c9SJ. Bruce Fields { 46277a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 46287a8711c9SJ. Bruce Fields return nfs_ok; 46297a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 46307a8711c9SJ. Bruce Fields return nfserr_replay_me; 46317a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 46327a8711c9SJ. Bruce Fields return nfs_ok; 46337a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 46347a8711c9SJ. Bruce Fields } 46351da177e4SLinus Torvalds 46364b24ca7dSJeff Layton static __be32 lookup_clientid(clientid_t *clid, 46374b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 4638b7342204SOlga Kornievskaia struct nfsd_net *nn, 4639b7342204SOlga Kornievskaia bool sessions) 46404b24ca7dSJeff Layton { 46414b24ca7dSJeff Layton struct nfs4_client *found; 46424b24ca7dSJeff Layton 46434b24ca7dSJeff Layton if (cstate->clp) { 46444b24ca7dSJeff Layton found = cstate->clp; 46454b24ca7dSJeff Layton if (!same_clid(&found->cl_clientid, clid)) 46464b24ca7dSJeff Layton return nfserr_stale_clientid; 46474b24ca7dSJeff Layton return nfs_ok; 46484b24ca7dSJeff Layton } 46494b24ca7dSJeff Layton 46504b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 46514b24ca7dSJeff Layton return nfserr_stale_clientid; 46524b24ca7dSJeff Layton 46534b24ca7dSJeff Layton /* 46544b24ca7dSJeff Layton * For v4.1+ we get the client in the SEQUENCE op. If we don't have one 46554b24ca7dSJeff Layton * cached already then we know this is for is for v4.0 and "sessions" 46564b24ca7dSJeff Layton * will be false. 46574b24ca7dSJeff Layton */ 46584b24ca7dSJeff Layton WARN_ON_ONCE(cstate->session); 46593e339f96STrond Myklebust spin_lock(&nn->client_lock); 4660b7342204SOlga Kornievskaia found = find_confirmed_client(clid, sessions, nn); 46613e339f96STrond Myklebust if (!found) { 46623e339f96STrond Myklebust spin_unlock(&nn->client_lock); 46634b24ca7dSJeff Layton return nfserr_expired; 46643e339f96STrond Myklebust } 466514ed14ccSJ. Bruce Fields atomic_inc(&found->cl_rpc_users); 46663e339f96STrond Myklebust spin_unlock(&nn->client_lock); 46674b24ca7dSJeff Layton 46684b24ca7dSJeff Layton /* Cache the nfs4_client in cstate! */ 46694b24ca7dSJeff Layton cstate->clp = found; 46704b24ca7dSJeff Layton return nfs_ok; 46714b24ca7dSJeff Layton } 46724b24ca7dSJeff Layton 4673b37ad28bSAl Viro __be32 46746668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 46753320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 46761da177e4SLinus Torvalds { 46771da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 46781da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 46791da177e4SLinus Torvalds unsigned int strhashval; 4680fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 46814cdc951bSJ. Bruce Fields __be32 status; 46821da177e4SLinus Torvalds 46832c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&open->op_clientid, nn)) 46841da177e4SLinus Torvalds return nfserr_stale_clientid; 468532513b40SJ. Bruce Fields /* 468632513b40SJ. Bruce Fields * In case we need it later, after we've already created the 468732513b40SJ. Bruce Fields * file and don't want to risk a further failure: 468832513b40SJ. Bruce Fields */ 468932513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 469032513b40SJ. Bruce Fields if (open->op_file == NULL) 469132513b40SJ. Bruce Fields return nfserr_jukebox; 46921da177e4SLinus Torvalds 4693b7342204SOlga Kornievskaia status = lookup_clientid(clientid, cstate, nn, false); 469413d6f66bSTrond Myklebust if (status) 469513d6f66bSTrond Myklebust return status; 469613d6f66bSTrond Myklebust clp = cstate->clp; 46972d91e895STrond Myklebust 4698d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 4699d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 47002d91e895STrond Myklebust open->op_openowner = oo; 47012d91e895STrond Myklebust if (!oo) { 4702bcf130f9SJ. Bruce Fields goto new_owner; 47030f442aa2SJ. Bruce Fields } 4704dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 47050f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 4706fe0750e5SJ. Bruce Fields release_openowner(oo); 4707fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 4708bcf130f9SJ. Bruce Fields goto new_owner; 47090f442aa2SJ. Bruce Fields } 47104cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 47114cdc951bSJ. Bruce Fields if (status) 47124cdc951bSJ. Bruce Fields return status; 47134cdc951bSJ. Bruce Fields goto alloc_stateid; 4714bcf130f9SJ. Bruce Fields new_owner: 471513d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 4716fe0750e5SJ. Bruce Fields if (oo == NULL) 47173e772463SJ. Bruce Fields return nfserr_jukebox; 4718fe0750e5SJ. Bruce Fields open->op_openowner = oo; 47194cdc951bSJ. Bruce Fields alloc_stateid: 4720b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 47214cdc951bSJ. Bruce Fields if (!open->op_stp) 47224cdc951bSJ. Bruce Fields return nfserr_jukebox; 47238287f009SSachin Bhamare 47248287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 47258287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 47268287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 47278287f009SSachin Bhamare if (!open->op_odstate) 47288287f009SSachin Bhamare return nfserr_jukebox; 47298287f009SSachin Bhamare } 47308287f009SSachin Bhamare 47310f442aa2SJ. Bruce Fields return nfs_ok; 47321da177e4SLinus Torvalds } 47331da177e4SLinus Torvalds 4734b37ad28bSAl Viro static inline __be32 47354a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 47364a6e43e6SNeilBrown { 47374a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 47384a6e43e6SNeilBrown return nfserr_openmode; 47394a6e43e6SNeilBrown else 47404a6e43e6SNeilBrown return nfs_ok; 47414a6e43e6SNeilBrown } 47424a6e43e6SNeilBrown 4743c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 474424a0111eSJ. Bruce Fields { 474524a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 474624a0111eSJ. Bruce Fields } 474724a0111eSJ. Bruce Fields 474838c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 4749f459e453SJ. Bruce Fields { 4750f459e453SJ. Bruce Fields struct nfs4_stid *ret; 4751f459e453SJ. Bruce Fields 475295da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 475395da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 4754f459e453SJ. Bruce Fields if (!ret) 4755f459e453SJ. Bruce Fields return NULL; 4756f459e453SJ. Bruce Fields return delegstateid(ret); 4757f459e453SJ. Bruce Fields } 4758f459e453SJ. Bruce Fields 47598b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 47608b289b2cSJ. Bruce Fields { 47618b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 47628b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 47638b289b2cSJ. Bruce Fields } 47648b289b2cSJ. Bruce Fields 4765b37ad28bSAl Viro static __be32 476641d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 4767567d9829SNeilBrown struct nfs4_delegation **dp) 4768567d9829SNeilBrown { 4769567d9829SNeilBrown int flags; 4770b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 4771dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 4772567d9829SNeilBrown 4773dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 4774dcd94cc2STrond Myklebust if (deleg == NULL) 4775c44c5eebSNeilBrown goto out; 477695da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 477795da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 477895da1b3aSAndrew Elble if (cl->cl_minorversion) 477995da1b3aSAndrew Elble status = nfserr_deleg_revoked; 478095da1b3aSAndrew Elble goto out; 478195da1b3aSAndrew Elble } 478224a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 4783dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 4784dcd94cc2STrond Myklebust if (status) { 4785dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 4786dcd94cc2STrond Myklebust goto out; 4787dcd94cc2STrond Myklebust } 4788dcd94cc2STrond Myklebust *dp = deleg; 4789c44c5eebSNeilBrown out: 47908b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 4791c44c5eebSNeilBrown return nfs_ok; 4792c44c5eebSNeilBrown if (status) 4793c44c5eebSNeilBrown return status; 4794dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 4795c44c5eebSNeilBrown return nfs_ok; 4796567d9829SNeilBrown } 4797567d9829SNeilBrown 479821fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 479921fb4016SJ. Bruce Fields { 480021fb4016SJ. Bruce Fields int flags = 0; 480121fb4016SJ. Bruce Fields 480221fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 480321fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 480421fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 480521fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 480621fb4016SJ. Bruce Fields return flags; 480721fb4016SJ. Bruce Fields } 480821fb4016SJ. Bruce Fields 4809b37ad28bSAl Viro static inline __be32 48101da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 48111da177e4SLinus Torvalds struct nfsd4_open *open) 48121da177e4SLinus Torvalds { 48131da177e4SLinus Torvalds struct iattr iattr = { 48141da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 48151da177e4SLinus Torvalds .ia_size = 0, 48161da177e4SLinus Torvalds }; 48171da177e4SLinus Torvalds if (!open->op_truncate) 48181da177e4SLinus Torvalds return 0; 48191da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 48209246585aSAl Viro return nfserr_inval; 48212a1aa489SArnd Bergmann return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0); 48221da177e4SLinus Torvalds } 48231da177e4SLinus Torvalds 48247e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 48256eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 48266eb3a1d0SJeff Layton struct nfsd4_open *open) 48277e6a72e5SChristoph Hellwig { 4828fd4f83fdSJeff Layton struct nfsd_file *nf = NULL; 48297e6a72e5SChristoph Hellwig __be32 status; 48307e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 48317e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 4832baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 48337e6a72e5SChristoph Hellwig 4834de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4835baeb4ff0SJeff Layton 4836baeb4ff0SJeff Layton /* 4837baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 4838baeb4ff0SJeff Layton * current access? 4839baeb4ff0SJeff Layton */ 4840baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4841baeb4ff0SJeff Layton if (status != nfs_ok) { 4842baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4843baeb4ff0SJeff Layton goto out; 4844baeb4ff0SJeff Layton } 4845baeb4ff0SJeff Layton 4846baeb4ff0SJeff Layton /* set access to the file */ 4847baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 4848baeb4ff0SJeff Layton if (status != nfs_ok) { 4849baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 4850baeb4ff0SJeff Layton goto out; 4851baeb4ff0SJeff Layton } 4852baeb4ff0SJeff Layton 4853baeb4ff0SJeff Layton /* Set access bits in stateid */ 4854baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 4855baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 4856baeb4ff0SJeff Layton 4857baeb4ff0SJeff Layton /* Set new deny mask */ 4858baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 4859baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4860baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 4861baeb4ff0SJeff Layton 48627e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 4863de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4864fd4f83fdSJeff Layton status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); 48657e6a72e5SChristoph Hellwig if (status) 4866baeb4ff0SJeff Layton goto out_put_access; 4867de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 4868de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 4869fd4f83fdSJeff Layton fp->fi_fds[oflag] = nf; 4870fd4f83fdSJeff Layton nf = NULL; 4871de18643dSTrond Myklebust } 48727e6a72e5SChristoph Hellwig } 4873de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 4874fd4f83fdSJeff Layton if (nf) 4875fd4f83fdSJeff Layton nfsd_file_put(nf); 48767e6a72e5SChristoph Hellwig 48777e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 48787e6a72e5SChristoph Hellwig if (status) 48797e6a72e5SChristoph Hellwig goto out_put_access; 48807e6a72e5SChristoph Hellwig out: 48817e6a72e5SChristoph Hellwig return status; 4882baeb4ff0SJeff Layton out_put_access: 4883baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 4884baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 4885baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 4886baeb4ff0SJeff Layton goto out; 48877e6a72e5SChristoph Hellwig } 48887e6a72e5SChristoph Hellwig 4889b37ad28bSAl Viro static __be32 4890dcef0413SJ. 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) 48911da177e4SLinus Torvalds { 4892b37ad28bSAl Viro __be32 status; 48936ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 48941da177e4SLinus Torvalds 48956eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 4896baeb4ff0SJeff Layton return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); 48977e6a72e5SChristoph Hellwig 4898baeb4ff0SJeff Layton /* test and set deny mode */ 4899baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 4900baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 4901baeb4ff0SJeff Layton if (status == nfs_ok) { 4902baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 4903baeb4ff0SJeff Layton fp->fi_share_deny |= 4904baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 49051da177e4SLinus Torvalds } 4906baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 49071da177e4SLinus Torvalds 4908baeb4ff0SJeff Layton if (status != nfs_ok) 4909baeb4ff0SJeff Layton return status; 4910baeb4ff0SJeff Layton 4911baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 4912baeb4ff0SJeff Layton if (status != nfs_ok) 4913baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 4914baeb4ff0SJeff Layton return status; 4915baeb4ff0SJeff Layton } 49161da177e4SLinus Torvalds 491714a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 491814a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 491914a24e99SJ. Bruce Fields { 492014a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 492114a24e99SJ. Bruce Fields return true; 492214a24e99SJ. Bruce Fields /* 492314a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 492414a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 492514a24e99SJ. Bruce Fields * until we hear otherwise: 492614a24e99SJ. Bruce Fields */ 492714a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 492814a24e99SJ. Bruce Fields } 492914a24e99SJ. Bruce Fields 4930653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 4931653e514eSJ. Bruce Fields int flag) 493222d38c4cSJ. Bruce Fields { 493322d38c4cSJ. Bruce Fields struct file_lock *fl; 493422d38c4cSJ. Bruce Fields 493522d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 493622d38c4cSJ. Bruce Fields if (!fl) 493722d38c4cSJ. Bruce Fields return NULL; 493822d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 4939617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 494022d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 494122d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 4942653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 494322d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 4944eb82dd39SJeff Layton fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; 494522d38c4cSJ. Bruce Fields return fl; 494622d38c4cSJ. Bruce Fields } 494722d38c4cSJ. Bruce Fields 494894415b06SJ. Bruce Fields static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, 494994415b06SJ. Bruce Fields struct nfs4_file *fp) 495094415b06SJ. Bruce Fields { 495194415b06SJ. Bruce Fields struct nfs4_clnt_odstate *co; 495294415b06SJ. Bruce Fields struct file *f = fp->fi_deleg_file->nf_file; 495394415b06SJ. Bruce Fields struct inode *ino = locks_inode(f); 495494415b06SJ. Bruce Fields int writes = atomic_read(&ino->i_writecount); 495594415b06SJ. Bruce Fields 495694415b06SJ. Bruce Fields if (fp->fi_fds[O_WRONLY]) 495794415b06SJ. Bruce Fields writes--; 495894415b06SJ. Bruce Fields if (fp->fi_fds[O_RDWR]) 495994415b06SJ. Bruce Fields writes--; 496094415b06SJ. Bruce Fields if (writes > 0) 496194415b06SJ. Bruce Fields return -EAGAIN; 496294415b06SJ. Bruce Fields spin_lock(&fp->fi_lock); 496394415b06SJ. Bruce Fields list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 496494415b06SJ. Bruce Fields if (co->co_client != clp) { 496594415b06SJ. Bruce Fields spin_unlock(&fp->fi_lock); 496694415b06SJ. Bruce Fields return -EAGAIN; 496794415b06SJ. Bruce Fields } 496894415b06SJ. Bruce Fields } 496994415b06SJ. Bruce Fields spin_unlock(&fp->fi_lock); 497094415b06SJ. Bruce Fields return 0; 497194415b06SJ. Bruce Fields } 497294415b06SJ. Bruce Fields 49730b26693cSJeff Layton static struct nfs4_delegation * 49740b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 49758287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 4976acfdf5c3SJ. Bruce Fields { 497768b18f52SJ. Bruce Fields int status = 0; 49780b26693cSJeff Layton struct nfs4_delegation *dp; 4979eb82dd39SJeff Layton struct nfsd_file *nf; 4980353601e7SJ. Bruce Fields struct file_lock *fl; 4981417c6629SJeff Layton 4982353601e7SJ. Bruce Fields /* 4983353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 4984353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 4985353601e7SJ. Bruce Fields * the end: 4986353601e7SJ. Bruce Fields */ 4987bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 49880b26693cSJeff Layton return ERR_PTR(-EAGAIN); 49890b26693cSJeff Layton 4990eb82dd39SJeff Layton nf = find_readable_file(fp); 4991eb82dd39SJeff Layton if (!nf) { 499294415b06SJ. Bruce Fields /* 499394415b06SJ. Bruce Fields * We probably could attempt another open and get a read 499494415b06SJ. Bruce Fields * delegation, but for now, don't bother until the 499594415b06SJ. Bruce Fields * client actually sends us one. 499694415b06SJ. Bruce Fields */ 499794415b06SJ. Bruce Fields return ERR_PTR(-EAGAIN); 4998353601e7SJ. Bruce Fields } 499934ed9872SAndrew Elble spin_lock(&state_lock); 500034ed9872SAndrew Elble spin_lock(&fp->fi_lock); 500168b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 500268b18f52SJ. Bruce Fields status = -EAGAIN; 5003353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 5004eb82dd39SJeff Layton fp->fi_deleg_file = nf; 5005353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 5006353601e7SJ. Bruce Fields * cleared */ 5007353601e7SJ. Bruce Fields fp->fi_delegees = 1; 5008eb82dd39SJeff Layton nf = NULL; 5009353601e7SJ. Bruce Fields } else 5010353601e7SJ. Bruce Fields fp->fi_delegees++; 5011353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 5012353601e7SJ. Bruce Fields spin_unlock(&state_lock); 5013eb82dd39SJeff Layton if (nf) 5014eb82dd39SJeff Layton nfsd_file_put(nf); 5015353601e7SJ. Bruce Fields if (status) 5016353601e7SJ. Bruce Fields return ERR_PTR(status); 5017353601e7SJ. Bruce Fields 5018353601e7SJ. Bruce Fields status = -ENOMEM; 5019353601e7SJ. Bruce Fields dp = alloc_init_deleg(clp, fp, fh, odstate); 5020353601e7SJ. Bruce Fields if (!dp) 5021353601e7SJ. Bruce Fields goto out_delegees; 5022353601e7SJ. Bruce Fields 5023353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 5024353601e7SJ. Bruce Fields if (!fl) 5025bd8d7250SAndrew Elble goto out_clnt_odstate; 5026353601e7SJ. Bruce Fields 502794415b06SJ. Bruce Fields status = nfsd4_check_conflicting_opens(clp, fp); 502894415b06SJ. Bruce Fields if (status) { 502994415b06SJ. Bruce Fields locks_free_lock(fl); 503094415b06SJ. Bruce Fields goto out_clnt_odstate; 503194415b06SJ. Bruce Fields } 5032eb82dd39SJeff Layton status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); 5033353601e7SJ. Bruce Fields if (fl) 5034353601e7SJ. Bruce Fields locks_free_lock(fl); 5035353601e7SJ. Bruce Fields if (status) 5036353601e7SJ. Bruce Fields goto out_clnt_odstate; 503794415b06SJ. Bruce Fields status = nfsd4_check_conflicting_opens(clp, fp); 503894415b06SJ. Bruce Fields if (status) 503994415b06SJ. Bruce Fields goto out_clnt_odstate; 5040353601e7SJ. Bruce Fields 5041353601e7SJ. Bruce Fields spin_lock(&state_lock); 5042353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 5043353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 5044353601e7SJ. Bruce Fields status = -EAGAIN; 5045353601e7SJ. Bruce Fields else 5046353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 504734ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 504834ed9872SAndrew Elble spin_unlock(&state_lock); 504934ed9872SAndrew Elble 505034ed9872SAndrew Elble if (status) 5051692ad280SAndrew Elble goto out_unlock; 5052692ad280SAndrew Elble 50530b26693cSJeff Layton return dp; 5054692ad280SAndrew Elble out_unlock: 5055eb82dd39SJeff Layton vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); 5056353601e7SJ. Bruce Fields out_clnt_odstate: 5057353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 5058353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 5059353601e7SJ. Bruce Fields out_delegees: 5060353601e7SJ. Bruce Fields put_deleg_file(fp); 5061353601e7SJ. Bruce Fields return ERR_PTR(status); 5062edab9782SJ. Bruce Fields } 5063edab9782SJ. Bruce Fields 50644aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 50654aa8913cSBenny Halevy { 50664aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 50674aa8913cSBenny Halevy if (status == -EAGAIN) 50684aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 50694aa8913cSBenny Halevy else { 50704aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 50714aa8913cSBenny Halevy switch (open->op_deleg_want) { 50724aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 50734aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 50744aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 50754aa8913cSBenny Halevy break; 50764aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 50774aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 50784aa8913cSBenny Halevy break; 50794aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 5080063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 50814aa8913cSBenny Halevy } 50824aa8913cSBenny Halevy } 50834aa8913cSBenny Halevy } 50844aa8913cSBenny Halevy 50851da177e4SLinus Torvalds /* 50861da177e4SLinus Torvalds * Attempt to hand out a delegation. 508799c41515SJ. Bruce Fields * 508899c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 508999c41515SJ. Bruce Fields * proper support for them. 50901da177e4SLinus Torvalds */ 50911da177e4SLinus Torvalds static void 50924cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 50934cf59221SJeff Layton struct nfs4_ol_stateid *stp) 50941da177e4SLinus Torvalds { 50951da177e4SLinus Torvalds struct nfs4_delegation *dp; 50964cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 50974cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 509814a24e99SJ. Bruce Fields int cb_up; 509999c41515SJ. Bruce Fields int status = 0; 51001da177e4SLinus Torvalds 5101fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 51027b190fecSNeilBrown open->op_recall = 0; 51037b190fecSNeilBrown switch (open->op_claim_type) { 51047b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 51052bf23875SJ. Bruce Fields if (!cb_up) 51067b190fecSNeilBrown open->op_recall = 1; 510799c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 510899c41515SJ. Bruce Fields goto out_no_deleg; 51097b190fecSNeilBrown break; 51107b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 5111ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 511299c41515SJ. Bruce Fields /* 511399c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 5114c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 5115c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 511699c41515SJ. Bruce Fields */ 51174cf59221SJeff Layton if (locks_in_grace(clp->net)) 511899c41515SJ. Bruce Fields goto out_no_deleg; 5119dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 512099c41515SJ. Bruce Fields goto out_no_deleg; 51217b190fecSNeilBrown break; 51227b190fecSNeilBrown default: 512399c41515SJ. Bruce Fields goto out_no_deleg; 51247b190fecSNeilBrown } 51258287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 51260b26693cSJeff Layton if (IS_ERR(dp)) 5127dd239cc0SJ. Bruce Fields goto out_no_deleg; 51281da177e4SLinus Torvalds 5129d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 51301da177e4SLinus Torvalds 51313caf9175SHou Tao trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); 513299c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 513367cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5134dd239cc0SJ. Bruce Fields return; 5135dd239cc0SJ. Bruce Fields out_no_deleg: 513699c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 51377b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 5138d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 51391da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 5140d08d32e6SJ. Bruce Fields open->op_recall = 1; 5141d08d32e6SJ. Bruce Fields } 5142dd239cc0SJ. Bruce Fields 5143dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 5144dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 5145dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 5146dd239cc0SJ. Bruce Fields return; 51471da177e4SLinus Torvalds } 51481da177e4SLinus Torvalds 5149e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 5150e27f49c3SBenny Halevy struct nfs4_delegation *dp) 5151e27f49c3SBenny Halevy { 5152e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 5153e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5154e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5155e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 5156e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 5157e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5158e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5159e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 5160e27f49c3SBenny Halevy } 5161e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 5162e27f49c3SBenny Halevy * it already has, therefore we don't return 5163e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 5164e27f49c3SBenny Halevy */ 5165e27f49c3SBenny Halevy } 5166e27f49c3SBenny Halevy 5167b37ad28bSAl Viro __be32 51681da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 51691da177e4SLinus Torvalds { 51706668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 517138c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 51721da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 5173dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 5174567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 5175b37ad28bSAl Viro __be32 status; 5176d8a1a000STrond Myklebust bool new_stp = false; 51771da177e4SLinus Torvalds 51781da177e4SLinus Torvalds /* 51791da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 51801da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 51811da177e4SLinus Torvalds * If not found, create the nfs4_file struct 51821da177e4SLinus Torvalds */ 5183f9c00c3aSJeff Layton fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); 5184950e0118STrond Myklebust if (fp != open->op_file) { 518541d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 5186c44c5eebSNeilBrown if (status) 5187c44c5eebSNeilBrown goto out; 518815ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 51891da177e4SLinus Torvalds } else { 5190950e0118STrond Myklebust open->op_file = NULL; 5191c44c5eebSNeilBrown status = nfserr_bad_stateid; 51928b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 5193c44c5eebSNeilBrown goto out; 51941da177e4SLinus Torvalds } 51951da177e4SLinus Torvalds 5196d8a1a000STrond Myklebust if (!stp) { 5197d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 5198d8a1a000STrond Myklebust if (!open->op_stp) 5199d8a1a000STrond Myklebust new_stp = true; 5200d8a1a000STrond Myklebust } 5201d8a1a000STrond Myklebust 52021da177e4SLinus Torvalds /* 52031da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 52041da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 5205d8a1a000STrond Myklebust * 5206d8a1a000STrond Myklebust * stp is already locked. 52071da177e4SLinus Torvalds */ 5208d8a1a000STrond Myklebust if (!new_stp) { 52091da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 5210f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 521135a92fe8SJeff Layton if (status) { 5212feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 52131da177e4SLinus Torvalds goto out; 521435a92fe8SJeff Layton } 52151da177e4SLinus Torvalds } else { 52166eb3a1d0SJeff Layton status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 52176eb3a1d0SJeff Layton if (status) { 5218d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 52196eb3a1d0SJeff Layton release_open_stateid(stp); 5220d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 52216eb3a1d0SJeff Layton goto out; 52226eb3a1d0SJeff Layton } 52238287f009SSachin Bhamare 52248287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 52258287f009SSachin Bhamare open->op_odstate); 52268287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 52278287f009SSachin Bhamare open->op_odstate = NULL; 52281da177e4SLinus Torvalds } 5229d8a1a000STrond Myklebust 52309767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 5231feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 52321da177e4SLinus Torvalds 5233d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 5234d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 5235d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5236d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 5237d24433cdSBenny Halevy goto nodeleg; 5238d24433cdSBenny Halevy } 5239d24433cdSBenny Halevy } 5240d24433cdSBenny Halevy 52411da177e4SLinus Torvalds /* 52421da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 52431da177e4SLinus Torvalds * OPEN succeeds even if we fail. 52441da177e4SLinus Torvalds */ 52454cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 5246d24433cdSBenny Halevy nodeleg: 52471da177e4SLinus Torvalds status = nfs_ok; 52483caf9175SHou Tao trace_nfsd_open(&stp->st_stid.sc_stateid); 52491da177e4SLinus Torvalds out: 5250d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 5251d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 5252e27f49c3SBenny Halevy open->op_deleg_want) 5253e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 5254d24433cdSBenny Halevy 525513cd2184SNeilBrown if (fp) 525613cd2184SNeilBrown put_nfs4_file(fp); 525737515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 525887186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 52591da177e4SLinus Torvalds /* 52601da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 52611da177e4SLinus Torvalds */ 52621da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 526319e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 526419e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 526519e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 52661da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 526719e4c347SJeff Layton 5268dcd94cc2STrond Myklebust if (dp) 5269dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5270d6f2bc5dSTrond Myklebust if (stp) 5271d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 52721da177e4SLinus Torvalds 52731da177e4SLinus Torvalds return status; 52741da177e4SLinus Torvalds } 52751da177e4SLinus Torvalds 527658fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 527742297899SJeff Layton struct nfsd4_open *open) 5278d29b20cdSJ. Bruce Fields { 5279d29b20cdSJ. Bruce Fields if (open->op_openowner) { 5280d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 5281d29b20cdSJ. Bruce Fields 5282d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 5283d3134b10SJeff Layton nfs4_put_stateowner(so); 5284d29b20cdSJ. Bruce Fields } 528532513b40SJ. Bruce Fields if (open->op_file) 52865b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 52874cdc951bSJ. Bruce Fields if (open->op_stp) 52886011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 52898287f009SSachin Bhamare if (open->op_odstate) 52908287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 5291d29b20cdSJ. Bruce Fields } 5292d29b20cdSJ. Bruce Fields 5293b37ad28bSAl Viro __be32 5294b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5295eb69853dSChristoph Hellwig union nfsd4_op_u *u) 52961da177e4SLinus Torvalds { 5297eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 52981da177e4SLinus Torvalds struct nfs4_client *clp; 5299b37ad28bSAl Viro __be32 status; 53007f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 53011da177e4SLinus Torvalds 5302dd5e3fbcSChuck Lever trace_nfsd_clid_renew(clid); 5303b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 53049b2ef62bSJ. Bruce Fields if (status) 53051da177e4SLinus Torvalds goto out; 53064b24ca7dSJeff Layton clp = cstate->clp; 53071da177e4SLinus Torvalds status = nfserr_cb_path_down; 5308ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 530977a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 53101da177e4SLinus Torvalds goto out; 53111da177e4SLinus Torvalds status = nfs_ok; 53121da177e4SLinus Torvalds out: 53131da177e4SLinus Torvalds return status; 53141da177e4SLinus Torvalds } 53151da177e4SLinus Torvalds 53167f5ef2e9SJeff Layton void 531712760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 5318a76b4319SNeilBrown { 531933dcc481SJeff Layton /* do nothing if grace period already ended */ 5320a51c84edSStanislav Kinsbursky if (nn->grace_ended) 532133dcc481SJeff Layton return; 532233dcc481SJeff Layton 5323dd5e3fbcSChuck Lever trace_nfsd_grace_complete(nn); 5324a51c84edSStanislav Kinsbursky nn->grace_ended = true; 532570b28235SJ. Bruce Fields /* 532670b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 532770b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 532870b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 532970b28235SJ. Bruce Fields * 533070b28235SJ. Bruce Fields */ 5331919b8049SJeff Layton nfsd4_record_grace_done(nn); 533270b28235SJ. Bruce Fields /* 533370b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 533470b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 533570b28235SJ. Bruce Fields * of luck on the next boot. 533670b28235SJ. Bruce Fields * 533770b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 533870b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 533970b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 534070b28235SJ. Bruce Fields */ 53415e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 534270b28235SJ. Bruce Fields /* 534370b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 534470b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 534570b28235SJ. Bruce Fields * regular locking can resume. 534670b28235SJ. Bruce Fields */ 5347a76b4319SNeilBrown } 5348a76b4319SNeilBrown 534903f318caSJ. Bruce Fields /* 535003f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 535103f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 535203f318caSJ. Bruce Fields */ 535303f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 535403f318caSJ. Bruce Fields { 535520b7d86fSArnd Bergmann time64_t double_grace_period_end = nn->boot_time + 535620b7d86fSArnd Bergmann 2 * nn->nfsd4_lease; 535703f318caSJ. Bruce Fields 5358362063a5SScott Mayhew if (nn->track_reclaim_completes && 5359362063a5SScott Mayhew atomic_read(&nn->nr_reclaim_complete) == 5360362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) 5361362063a5SScott Mayhew return false; 536203f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 536303f318caSJ. Bruce Fields return false; 536403f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 536503f318caSJ. Bruce Fields /* 536603f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 536703f318caSJ. Bruce Fields * still not done, give up: 536803f318caSJ. Bruce Fields */ 536920b7d86fSArnd Bergmann if (ktime_get_boottime_seconds() > double_grace_period_end) 537003f318caSJ. Bruce Fields return false; 537103f318caSJ. Bruce Fields return true; 537203f318caSJ. Bruce Fields } 537303f318caSJ. Bruce Fields 537420b7d86fSArnd Bergmann static time64_t 537509121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 53761da177e4SLinus Torvalds { 53771da177e4SLinus Torvalds struct nfs4_client *clp; 5378fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 53791da177e4SLinus Torvalds struct nfs4_delegation *dp; 5380217526e7SJeff Layton struct nfs4_ol_stateid *stp; 53817919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 53821da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 538320b7d86fSArnd Bergmann time64_t cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease; 538420b7d86fSArnd Bergmann time64_t t, new_timeo = nn->nfsd4_lease; 5385624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 5386624322f1SOlga Kornievskaia copy_stateid_t *cps_t; 5387624322f1SOlga Kornievskaia int i; 53881da177e4SLinus Torvalds 538903f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 539003f318caSJ. Bruce Fields new_timeo = 0; 539103f318caSJ. Bruce Fields goto out; 539203f318caSJ. Bruce Fields } 539312760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 539436acb66bSBenny Halevy INIT_LIST_HEAD(&reaplist); 5395624322f1SOlga Kornievskaia 5396624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5397624322f1SOlga Kornievskaia idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { 5398624322f1SOlga Kornievskaia cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); 5399624322f1SOlga Kornievskaia if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID && 540020b7d86fSArnd Bergmann cps->cpntf_time > cutoff) 5401624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 5402624322f1SOlga Kornievskaia } 5403624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5404624322f1SOlga Kornievskaia 5405c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 54065ed58bb2SStanislav Kinsbursky list_for_each_safe(pos, next, &nn->client_lru) { 54071da177e4SLinus Torvalds clp = list_entry(pos, struct nfs4_client, cl_lru); 540820b7d86fSArnd Bergmann if (clp->cl_time > cutoff) { 54091da177e4SLinus Torvalds t = clp->cl_time - cutoff; 5410a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 54111da177e4SLinus Torvalds break; 54121da177e4SLinus Torvalds } 5413221a6876SJ. Bruce Fields if (mark_client_expired_locked(clp)) { 5414dd5e3fbcSChuck Lever trace_nfsd_clid_expired(&clp->cl_clientid); 5415d7682988SBenny Halevy continue; 5416d7682988SBenny Halevy } 54174864af97STrond Myklebust list_add(&clp->cl_lru, &reaplist); 541836acb66bSBenny Halevy } 5419c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 542036acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 542136acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 5422dd5e3fbcSChuck Lever trace_nfsd_clid_purged(&clp->cl_clientid); 54234864af97STrond Myklebust list_del_init(&clp->cl_lru); 54241da177e4SLinus Torvalds expire_client(clp); 54251da177e4SLinus Torvalds } 5426cdc97505SBenny Halevy spin_lock(&state_lock); 5427e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 54281da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 542920b7d86fSArnd Bergmann if (dp->dl_time > cutoff) { 5430a832e7aeSJeff Layton t = dp->dl_time - cutoff; 5431a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 54321da177e4SLinus Torvalds break; 54331da177e4SLinus Torvalds } 54343fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 543542690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 54361da177e4SLinus Torvalds } 5437cdc97505SBenny Halevy spin_unlock(&state_lock); 54382d4a532dSJeff Layton while (!list_empty(&reaplist)) { 54392d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 54402d4a532dSJeff Layton dl_recall_lru); 54412d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 54423bd64a5bSJ. Bruce Fields revoke_delegation(dp); 54431da177e4SLinus Torvalds } 5444217526e7SJeff Layton 5445217526e7SJeff Layton spin_lock(&nn->client_lock); 5446217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 5447217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 5448217526e7SJeff Layton oo_close_lru); 544920b7d86fSArnd Bergmann if (oo->oo_time > cutoff) { 5450a832e7aeSJeff Layton t = oo->oo_time - cutoff; 5451a832e7aeSJeff Layton new_timeo = min(new_timeo, t); 54521da177e4SLinus Torvalds break; 54531da177e4SLinus Torvalds } 5454217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 5455217526e7SJeff Layton stp = oo->oo_last_closed_stid; 5456217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 5457217526e7SJeff Layton spin_unlock(&nn->client_lock); 5458217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 5459217526e7SJeff Layton spin_lock(&nn->client_lock); 54601da177e4SLinus Torvalds } 5461217526e7SJeff Layton spin_unlock(&nn->client_lock); 5462217526e7SJeff Layton 54637919d0a2SJeff Layton /* 54647919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 54657919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 54667919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 54677919d0a2SJeff Layton * under the assumption that the client is no longer interested. 54687919d0a2SJeff Layton * 54697919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 54707919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 54717919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 54727919d0a2SJeff Layton * indefinitely once the lock does become free. 54737919d0a2SJeff Layton */ 54747919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 54750cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 54767919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 54777919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 54787919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 547920b7d86fSArnd Bergmann if (nbl->nbl_time > cutoff) { 54807919d0a2SJeff Layton t = nbl->nbl_time - cutoff; 54817919d0a2SJeff Layton new_timeo = min(new_timeo, t); 54827919d0a2SJeff Layton break; 54837919d0a2SJeff Layton } 54847919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 54857919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 54867919d0a2SJeff Layton } 54870cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 54887919d0a2SJeff Layton 54897919d0a2SJeff Layton while (!list_empty(&reaplist)) { 549064ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 54917919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 54927919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 54937919d0a2SJeff Layton free_blocked_lock(nbl); 54947919d0a2SJeff Layton } 549503f318caSJ. Bruce Fields out: 549620b7d86fSArnd Bergmann new_timeo = max_t(time64_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 5497a832e7aeSJeff Layton return new_timeo; 54981da177e4SLinus Torvalds } 54991da177e4SLinus Torvalds 5500a254b246SHarvey Harrison static struct workqueue_struct *laundry_wq; 5501a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 5502a254b246SHarvey Harrison 5503a254b246SHarvey Harrison static void 550409121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 55051da177e4SLinus Torvalds { 550620b7d86fSArnd Bergmann time64_t t; 55072e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 550809121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 550909121281SStanislav Kinsbursky laundromat_work); 55101da177e4SLinus Torvalds 551109121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 551209121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 55131da177e4SLinus Torvalds } 55141da177e4SLinus Torvalds 55158fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 5516f8816512SNeilBrown { 55178fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 5518f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 5519f7a4d872SJ. Bruce Fields return nfs_ok; 55201da177e4SLinus Torvalds } 55211da177e4SLinus Torvalds 55221da177e4SLinus Torvalds static inline int 552382c5ff1bSJeff Layton access_permit_read(struct nfs4_ol_stateid *stp) 55241da177e4SLinus Torvalds { 552582c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_READ, stp) || 552682c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 552782c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_WRITE, stp); 55281da177e4SLinus Torvalds } 55291da177e4SLinus Torvalds 55301da177e4SLinus Torvalds static inline int 553182c5ff1bSJeff Layton access_permit_write(struct nfs4_ol_stateid *stp) 55321da177e4SLinus Torvalds { 553382c5ff1bSJeff Layton return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 553482c5ff1bSJeff Layton test_access(NFS4_SHARE_ACCESS_BOTH, stp); 55351da177e4SLinus Torvalds } 55361da177e4SLinus Torvalds 55371da177e4SLinus Torvalds static 5538dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 55391da177e4SLinus Torvalds { 5540b37ad28bSAl Viro __be32 status = nfserr_openmode; 55411da177e4SLinus Torvalds 554202921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 554302921914SJ. Bruce Fields if (stp->st_openstp) 554402921914SJ. Bruce Fields stp = stp->st_openstp; 554582c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 55461da177e4SLinus Torvalds goto out; 554782c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 55481da177e4SLinus Torvalds goto out; 55491da177e4SLinus Torvalds status = nfs_ok; 55501da177e4SLinus Torvalds out: 55511da177e4SLinus Torvalds return status; 55521da177e4SLinus Torvalds } 55531da177e4SLinus Torvalds 5554b37ad28bSAl Viro static inline __be32 55555ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 55561da177e4SLinus Torvalds { 5557203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 55581da177e4SLinus Torvalds return nfs_ok; 5559c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 556025985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 55611da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 55621da177e4SLinus Torvalds return nfserr_grace; 55631da177e4SLinus Torvalds } else if (flags & WR_STATE) 55641da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 55651da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 55661da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 55671da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 55681da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 55691da177e4SLinus Torvalds } 55701da177e4SLinus Torvalds 55711da177e4SLinus Torvalds /* 55721da177e4SLinus Torvalds * Allow READ/WRITE during grace period on recovered state only for files 55731da177e4SLinus Torvalds * that are not able to provide mandatory locking. 55741da177e4SLinus Torvalds */ 55751da177e4SLinus Torvalds static inline int 55765ccb0066SStanislav Kinsbursky grace_disallows_io(struct net *net, struct inode *inode) 55771da177e4SLinus Torvalds { 5578c87fb4a3SJ. Bruce Fields return opens_in_grace(net) && mandatory_lock(inode); 55791da177e4SLinus Torvalds } 55801da177e4SLinus Torvalds 558157b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 55820836f587SJ. Bruce Fields { 55836668958fSAndy Adamson /* 55846668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 55856668958fSAndy Adamson * when it is zero. 55866668958fSAndy Adamson */ 558728dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 558881b82965SJ. Bruce Fields return nfs_ok; 558981b82965SJ. Bruce Fields 559081b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 559181b82965SJ. Bruce Fields return nfs_ok; 55926668958fSAndy Adamson 55930836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 559414b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 55950836f587SJ. Bruce Fields return nfserr_bad_stateid; 55960836f587SJ. Bruce Fields /* 559781b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 559881b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 559981b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 560081b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 560181b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 560281b82965SJ. Bruce Fields * but better performance may result in retrying IO that 560381b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 560481b82965SJ. Bruce Fields * reordered in flight: 56050836f587SJ. Bruce Fields */ 56060836f587SJ. Bruce Fields return nfserr_old_stateid; 56070836f587SJ. Bruce Fields } 56080836f587SJ. Bruce Fields 560903da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 561003da3169STrond Myklebust { 561103da3169STrond Myklebust __be32 ret; 561203da3169STrond Myklebust 561303da3169STrond Myklebust spin_lock(&s->sc_lock); 561403da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 561503da3169STrond Myklebust if (ret == nfs_ok) 561603da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 561703da3169STrond Myklebust spin_unlock(&s->sc_lock); 561803da3169STrond Myklebust return ret; 561903da3169STrond Myklebust } 562003da3169STrond Myklebust 5621ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 5622ebe9cb3bSChristoph Hellwig { 5623ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 5624ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 5625ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 5626ebe9cb3bSChristoph Hellwig return nfs_ok; 5627ebe9cb3bSChristoph Hellwig } 5628ebe9cb3bSChristoph Hellwig 56297df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 563017456804SBryan Schumaker { 563197b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 56321af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 563317456804SBryan Schumaker 5634ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5635ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 56361af71cc8SJeff Layton return status; 5637663e36f0SJ. Bruce Fields if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) 56381af71cc8SJeff Layton return status; 56391af71cc8SJeff Layton spin_lock(&cl->cl_lock); 56401af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 564197b7e3b6SJ. Bruce Fields if (!s) 56421af71cc8SJeff Layton goto out_unlock; 564303da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 564417456804SBryan Schumaker if (status) 56451af71cc8SJeff Layton goto out_unlock; 564623340032SJ. Bruce Fields switch (s->sc_type) { 564723340032SJ. Bruce Fields case NFS4_DELEG_STID: 56481af71cc8SJeff Layton status = nfs_ok; 56491af71cc8SJeff Layton break; 56503bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 56511af71cc8SJeff Layton status = nfserr_deleg_revoked; 56521af71cc8SJeff Layton break; 565323340032SJ. Bruce Fields case NFS4_OPEN_STID: 565423340032SJ. Bruce Fields case NFS4_LOCK_STID: 5655ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 56561af71cc8SJeff Layton break; 565723340032SJ. Bruce Fields default: 565823340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 5659df561f66SGustavo A. R. Silva fallthrough; 566023340032SJ. Bruce Fields case NFS4_CLOSED_STID: 5661b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 56621af71cc8SJeff Layton status = nfserr_bad_stateid; 566323340032SJ. Bruce Fields } 56641af71cc8SJeff Layton out_unlock: 56651af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 56661af71cc8SJeff Layton return status; 566717456804SBryan Schumaker } 566817456804SBryan Schumaker 5669cd61c522SChristoph Hellwig __be32 56702dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 56712dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 56722dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 567338c2f4b1SJ. Bruce Fields { 56740eb6f20aSJ. Bruce Fields __be32 status; 567595da1b3aSAndrew Elble bool return_revoked = false; 567695da1b3aSAndrew Elble 567795da1b3aSAndrew Elble /* 567895da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 567995da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 568095da1b3aSAndrew Elble */ 568195da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 568295da1b3aSAndrew Elble return_revoked = true; 568395da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 568495da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 568538c2f4b1SJ. Bruce Fields 5686ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5687ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 568838c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 5689b7342204SOlga Kornievskaia status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn, 5690b7342204SOlga Kornievskaia false); 5691a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 56924b24ca7dSJeff Layton if (cstate->session) 5693a8a7c677STrond Myklebust return nfserr_bad_stateid; 569438c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 5695a8a7c677STrond Myklebust } 56960eb6f20aSJ. Bruce Fields if (status) 56970eb6f20aSJ. Bruce Fields return status; 56984b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 569938c2f4b1SJ. Bruce Fields if (!*s) 570038c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 570195da1b3aSAndrew Elble if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 570295da1b3aSAndrew Elble nfs4_put_stid(*s); 570395da1b3aSAndrew Elble if (cstate->minorversion) 570495da1b3aSAndrew Elble return nfserr_deleg_revoked; 570595da1b3aSAndrew Elble return nfserr_bad_stateid; 570695da1b3aSAndrew Elble } 570738c2f4b1SJ. Bruce Fields return nfs_ok; 570838c2f4b1SJ. Bruce Fields } 570938c2f4b1SJ. Bruce Fields 5710eb82dd39SJeff Layton static struct nfsd_file * 5711a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 5712a0649b2dSChristoph Hellwig { 5713af90f707SChristoph Hellwig if (!s) 5714af90f707SChristoph Hellwig return NULL; 5715af90f707SChristoph Hellwig 5716a0649b2dSChristoph Hellwig switch (s->sc_type) { 5717a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 5718a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 5719a0649b2dSChristoph Hellwig return NULL; 5720eb82dd39SJeff Layton return nfsd_file_get(s->sc_file->fi_deleg_file); 5721a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 5722a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 5723a0649b2dSChristoph Hellwig if (flags & RD_STATE) 5724a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 5725a0649b2dSChristoph Hellwig else 5726a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 5727a0649b2dSChristoph Hellwig } 5728a0649b2dSChristoph Hellwig 5729a0649b2dSChristoph Hellwig return NULL; 5730a0649b2dSChristoph Hellwig } 5731a0649b2dSChristoph Hellwig 5732a0649b2dSChristoph Hellwig static __be32 5733d8836f77SJ. Bruce Fields nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) 5734a0649b2dSChristoph Hellwig { 5735a0649b2dSChristoph Hellwig __be32 status; 5736a0649b2dSChristoph Hellwig 5737a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 5738a0649b2dSChristoph Hellwig if (status) 5739a0649b2dSChristoph Hellwig return status; 5740a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 5741a0649b2dSChristoph Hellwig } 5742a0649b2dSChristoph Hellwig 5743af90f707SChristoph Hellwig static __be32 5744af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 57455c4583b2SJeff Layton struct nfsd_file **nfp, int flags) 5746af90f707SChristoph Hellwig { 5747af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 5748eb82dd39SJeff Layton struct nfsd_file *nf; 5749af90f707SChristoph Hellwig __be32 status; 5750af90f707SChristoph Hellwig 5751eb82dd39SJeff Layton nf = nfs4_find_file(s, flags); 5752eb82dd39SJeff Layton if (nf) { 5753af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 5754af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 57555c4583b2SJeff Layton if (status) { 57565c4583b2SJeff Layton nfsd_file_put(nf); 5757eb82dd39SJeff Layton goto out; 57585c4583b2SJeff Layton } 5759af90f707SChristoph Hellwig } else { 5760eb82dd39SJeff Layton status = nfsd_file_acquire(rqstp, fhp, acc, &nf); 5761af90f707SChristoph Hellwig if (status) 5762af90f707SChristoph Hellwig return status; 5763af90f707SChristoph Hellwig } 57645c4583b2SJeff Layton *nfp = nf; 5765eb82dd39SJeff Layton out: 5766eb82dd39SJeff Layton return status; 5767af90f707SChristoph Hellwig } 5768624322f1SOlga Kornievskaia static void 5769624322f1SOlga Kornievskaia _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 5770624322f1SOlga Kornievskaia { 5771624322f1SOlga Kornievskaia WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID); 5772624322f1SOlga Kornievskaia if (!refcount_dec_and_test(&cps->cp_stateid.sc_count)) 5773624322f1SOlga Kornievskaia return; 5774624322f1SOlga Kornievskaia list_del(&cps->cp_list); 5775624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 5776624322f1SOlga Kornievskaia cps->cp_stateid.stid.si_opaque.so_id); 5777624322f1SOlga Kornievskaia kfree(cps); 5778624322f1SOlga Kornievskaia } 5779b7342204SOlga Kornievskaia /* 5780b7342204SOlga Kornievskaia * A READ from an inter server to server COPY will have a 5781b7342204SOlga Kornievskaia * copy stateid. Look up the copy notify stateid from the 5782b7342204SOlga Kornievskaia * idr structure and take a reference on it. 5783b7342204SOlga Kornievskaia */ 5784ce0887acSOlga Kornievskaia __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st, 5785ce0887acSOlga Kornievskaia struct nfs4_client *clp, 5786b7342204SOlga Kornievskaia struct nfs4_cpntf_state **cps) 5787b7342204SOlga Kornievskaia { 5788b7342204SOlga Kornievskaia copy_stateid_t *cps_t; 5789b7342204SOlga Kornievskaia struct nfs4_cpntf_state *state = NULL; 5790b7342204SOlga Kornievskaia 5791b7342204SOlga Kornievskaia if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id) 5792b7342204SOlga Kornievskaia return nfserr_bad_stateid; 5793b7342204SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5794b7342204SOlga Kornievskaia cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id); 5795b7342204SOlga Kornievskaia if (cps_t) { 5796b7342204SOlga Kornievskaia state = container_of(cps_t, struct nfs4_cpntf_state, 5797b7342204SOlga Kornievskaia cp_stateid); 57985277a79eSDan Carpenter if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID) { 57995277a79eSDan Carpenter state = NULL; 58005277a79eSDan Carpenter goto unlock; 58015277a79eSDan Carpenter } 5802ce0887acSOlga Kornievskaia if (!clp) 5803b7342204SOlga Kornievskaia refcount_inc(&state->cp_stateid.sc_count); 5804ce0887acSOlga Kornievskaia else 5805ce0887acSOlga Kornievskaia _free_cpntf_state_locked(nn, state); 5806b7342204SOlga Kornievskaia } 58075277a79eSDan Carpenter unlock: 5808b7342204SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5809b7342204SOlga Kornievskaia if (!state) 5810b7342204SOlga Kornievskaia return nfserr_bad_stateid; 5811ce0887acSOlga Kornievskaia if (!clp && state) 5812b7342204SOlga Kornievskaia *cps = state; 5813b7342204SOlga Kornievskaia return 0; 5814b7342204SOlga Kornievskaia } 5815b7342204SOlga Kornievskaia 5816b7342204SOlga Kornievskaia static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, 5817b7342204SOlga Kornievskaia struct nfs4_stid **stid) 5818b7342204SOlga Kornievskaia { 5819b7342204SOlga Kornievskaia __be32 status; 5820b7342204SOlga Kornievskaia struct nfs4_cpntf_state *cps = NULL; 5821b7342204SOlga Kornievskaia struct nfsd4_compound_state cstate; 5822b7342204SOlga Kornievskaia 5823ce0887acSOlga Kornievskaia status = manage_cpntf_state(nn, st, NULL, &cps); 5824b7342204SOlga Kornievskaia if (status) 5825b7342204SOlga Kornievskaia return status; 5826b7342204SOlga Kornievskaia 582720b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 5828b7342204SOlga Kornievskaia memset(&cstate, 0, sizeof(cstate)); 5829b7342204SOlga Kornievskaia status = lookup_clientid(&cps->cp_p_clid, &cstate, nn, true); 5830b7342204SOlga Kornievskaia if (status) 5831b7342204SOlga Kornievskaia goto out; 5832b7342204SOlga Kornievskaia status = nfsd4_lookup_stateid(&cstate, &cps->cp_p_stateid, 5833b7342204SOlga Kornievskaia NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 5834b7342204SOlga Kornievskaia stid, nn); 5835b7342204SOlga Kornievskaia put_client_renew(cstate.clp); 5836b7342204SOlga Kornievskaia out: 5837b7342204SOlga Kornievskaia nfs4_put_cpntf_state(nn, cps); 5838b7342204SOlga Kornievskaia return status; 5839b7342204SOlga Kornievskaia } 5840624322f1SOlga Kornievskaia 5841624322f1SOlga Kornievskaia void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 5842624322f1SOlga Kornievskaia { 5843624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5844624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 5845624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 5846624322f1SOlga Kornievskaia } 5847af90f707SChristoph Hellwig 58481da177e4SLinus Torvalds /* 58491da177e4SLinus Torvalds * Checks for stateid operations 58501da177e4SLinus Torvalds */ 5851b37ad28bSAl Viro __be32 5852af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 5853aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 5854624322f1SOlga Kornievskaia stateid_t *stateid, int flags, struct nfsd_file **nfp, 5855624322f1SOlga Kornievskaia struct nfs4_stid **cstid) 58561da177e4SLinus Torvalds { 5857a0649b2dSChristoph Hellwig struct inode *ino = d_inode(fhp->fh_dentry); 5858af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 58593320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 5860af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 5861b37ad28bSAl Viro __be32 status; 58621da177e4SLinus Torvalds 58635c4583b2SJeff Layton if (nfp) 58645c4583b2SJeff Layton *nfp = NULL; 58651da177e4SLinus Torvalds 58665ccb0066SStanislav Kinsbursky if (grace_disallows_io(net, ino)) 58671da177e4SLinus Torvalds return nfserr_grace; 58681da177e4SLinus Torvalds 5869af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 5870af90f707SChristoph Hellwig status = check_special_stateids(net, fhp, stateid, flags); 5871af90f707SChristoph Hellwig goto done; 5872af90f707SChristoph Hellwig } 58731da177e4SLinus Torvalds 58742dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 5875db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 58762dd6e458STrond Myklebust &s, nn); 5877b7342204SOlga Kornievskaia if (status == nfserr_bad_stateid) 5878b7342204SOlga Kornievskaia status = find_cpntf_state(nn, stateid, &s); 587938c2f4b1SJ. Bruce Fields if (status) 5880c2d1d6a8STrond Myklebust return status; 588103da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 5882a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 58830c2a498fSJ. Bruce Fields if (status) 58840c2a498fSJ. Bruce Fields goto out; 5885a0649b2dSChristoph Hellwig 5886f7a4d872SJ. Bruce Fields switch (s->sc_type) { 5887f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 5888a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 5889f7a4d872SJ. Bruce Fields break; 5890f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 5891f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 5892d8836f77SJ. Bruce Fields status = nfs4_check_olstateid(openlockstateid(s), flags); 5893f7a4d872SJ. Bruce Fields break; 5894f7a4d872SJ. Bruce Fields default: 589514bcab1aSTrond Myklebust status = nfserr_bad_stateid; 5896a0649b2dSChristoph Hellwig break; 58971da177e4SLinus Torvalds } 58988fcd461dSJeff Layton if (status) 58998fcd461dSJeff Layton goto out; 59008fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 5901a0649b2dSChristoph Hellwig 5902af90f707SChristoph Hellwig done: 59035c4583b2SJeff Layton if (status == nfs_ok && nfp) 59045c4583b2SJeff Layton status = nfs4_check_file(rqstp, fhp, s, nfp, flags); 59051da177e4SLinus Torvalds out: 5906624322f1SOlga Kornievskaia if (s) { 5907624322f1SOlga Kornievskaia if (!status && cstid) 5908624322f1SOlga Kornievskaia *cstid = s; 5909624322f1SOlga Kornievskaia else 5910fd911011STrond Myklebust nfs4_put_stid(s); 5911624322f1SOlga Kornievskaia } 59121da177e4SLinus Torvalds return status; 59131da177e4SLinus Torvalds } 59141da177e4SLinus Torvalds 5915e1ca12dfSBryan Schumaker /* 591617456804SBryan Schumaker * Test if the stateid is valid 591717456804SBryan Schumaker */ 591817456804SBryan Schumaker __be32 591917456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5920eb69853dSChristoph Hellwig union nfsd4_op_u *u) 592117456804SBryan Schumaker { 5922eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 592303cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 592403cfb420SBryan Schumaker struct nfs4_client *cl = cstate->session->se_client; 592503cfb420SBryan Schumaker 592603cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 59277df302f7SChuck Lever stateid->ts_id_status = 59287df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 592903cfb420SBryan Schumaker 593017456804SBryan Schumaker return nfs_ok; 593117456804SBryan Schumaker } 593217456804SBryan Schumaker 593342691398SChuck Lever static __be32 593442691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 593542691398SChuck Lever { 593642691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 593742691398SChuck Lever __be32 ret; 593842691398SChuck Lever 5939659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 5940659aefb6STrond Myklebust if (ret) 5941659aefb6STrond Myklebust goto out_put_stid; 594242691398SChuck Lever 594342691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 594442691398SChuck Lever if (ret) 594542691398SChuck Lever goto out; 594642691398SChuck Lever 594742691398SChuck Lever ret = nfserr_locks_held; 594842691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 594942691398SChuck Lever lockowner(stp->st_stateowner))) 595042691398SChuck Lever goto out; 595142691398SChuck Lever 595242691398SChuck Lever release_lock_stateid(stp); 595342691398SChuck Lever ret = nfs_ok; 595442691398SChuck Lever 595542691398SChuck Lever out: 595642691398SChuck Lever mutex_unlock(&stp->st_mutex); 5957659aefb6STrond Myklebust out_put_stid: 595842691398SChuck Lever nfs4_put_stid(s); 595942691398SChuck Lever return ret; 596042691398SChuck Lever } 596142691398SChuck Lever 5962e1ca12dfSBryan Schumaker __be32 5963e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5964eb69853dSChristoph Hellwig union nfsd4_op_u *u) 5965e1ca12dfSBryan Schumaker { 5966eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 5967e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 59682da1cec7SJ. Bruce Fields struct nfs4_stid *s; 59693bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 597038c2f4b1SJ. Bruce Fields struct nfs4_client *cl = cstate->session->se_client; 59712da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 5972e1ca12dfSBryan Schumaker 59731af71cc8SJeff Layton spin_lock(&cl->cl_lock); 59741af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 59752da1cec7SJ. Bruce Fields if (!s) 59761af71cc8SJeff Layton goto out_unlock; 597703da3169STrond Myklebust spin_lock(&s->sc_lock); 59782da1cec7SJ. Bruce Fields switch (s->sc_type) { 59792da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 5980e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 59811af71cc8SJeff Layton break; 59822da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 59831af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 59841af71cc8SJeff Layton if (ret) 59851af71cc8SJeff Layton break; 59861af71cc8SJeff Layton ret = nfserr_locks_held; 59871af71cc8SJeff Layton break; 59882da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 598903da3169STrond Myklebust spin_unlock(&s->sc_lock); 5990a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 59911af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 599242691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 59931af71cc8SJeff Layton goto out; 59943bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 599503da3169STrond Myklebust spin_unlock(&s->sc_lock); 59963bd64a5bSJ. Bruce Fields dp = delegstateid(s); 59972d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 59982d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 59996011695dSTrond Myklebust nfs4_put_stid(s); 60003bd64a5bSJ. Bruce Fields ret = nfs_ok; 60011af71cc8SJeff Layton goto out; 60021af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 6003e1ca12dfSBryan Schumaker } 600403da3169STrond Myklebust spin_unlock(&s->sc_lock); 60051af71cc8SJeff Layton out_unlock: 60061af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 6007e1ca12dfSBryan Schumaker out: 6008e1ca12dfSBryan Schumaker return ret; 6009e1ca12dfSBryan Schumaker } 6010e1ca12dfSBryan Schumaker 60114c4cd222SNeilBrown static inline int 60124c4cd222SNeilBrown setlkflg (int type) 60134c4cd222SNeilBrown { 60144c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 60154c4cd222SNeilBrown RD_STATE : WR_STATE; 60164c4cd222SNeilBrown } 60171da177e4SLinus Torvalds 6018dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 6019c0a5d93eSJ. Bruce Fields { 6020c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 6021c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 6022c0a5d93eSJ. Bruce Fields __be32 status; 6023c0a5d93eSJ. Bruce Fields 6024c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 6025c0a5d93eSJ. Bruce Fields if (status) 6026c0a5d93eSJ. Bruce Fields return status; 60279271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 60289271d7e5STrond Myklebust if (status != nfs_ok) 60299271d7e5STrond Myklebust return status; 6030f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 603135a92fe8SJeff Layton if (status == nfs_ok) 603235a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 603335a92fe8SJeff Layton if (status != nfs_ok) 6034feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6035f7a4d872SJ. Bruce Fields return status; 6036c0a5d93eSJ. Bruce Fields } 6037c0a5d93eSJ. Bruce Fields 60381da177e4SLinus Torvalds /* 60391da177e4SLinus Torvalds * Checks for sequence id mutating operations. 60401da177e4SLinus Torvalds */ 6041b37ad28bSAl Viro static __be32 6042dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 60432288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 60443320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 60453320fef1SStanislav Kinsbursky struct nfsd_net *nn) 60461da177e4SLinus Torvalds { 60470836f587SJ. Bruce Fields __be32 status; 604838c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6049e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 60501da177e4SLinus Torvalds 6051dd5e3fbcSChuck Lever trace_nfsd_preprocess(seqid, stateid); 60521da177e4SLinus Torvalds 60531da177e4SLinus Torvalds *stpp = NULL; 60542dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 6055c0a5d93eSJ. Bruce Fields if (status) 6056c0a5d93eSJ. Bruce Fields return status; 6057e17f99b7STrond Myklebust stp = openlockstateid(s); 605858fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 60591da177e4SLinus Torvalds 6060e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 6061fd911011STrond Myklebust if (!status) 6062e17f99b7STrond Myklebust *stpp = stp; 6063fd911011STrond Myklebust else 6064fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 6065e17f99b7STrond Myklebust return status; 60661da177e4SLinus Torvalds } 60671da177e4SLinus Torvalds 60683320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 60693320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 6070c0a5d93eSJ. Bruce Fields { 6071c0a5d93eSJ. Bruce Fields __be32 status; 6072c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 60734cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 60741da177e4SLinus Torvalds 6075c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 60764cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 60770836f587SJ. Bruce Fields if (status) 60780836f587SJ. Bruce Fields return status; 60794cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 60804cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 6081feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 60824cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 6083c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 60844cbfc9f7STrond Myklebust } 60854cbfc9f7STrond Myklebust *stpp = stp; 60863a4f98bbSNeilBrown return nfs_ok; 60871da177e4SLinus Torvalds } 60881da177e4SLinus Torvalds 6089b37ad28bSAl Viro __be32 6090ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6091eb69853dSChristoph Hellwig union nfsd4_op_u *u) 60921da177e4SLinus Torvalds { 6093eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 6094b37ad28bSAl Viro __be32 status; 6095fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 6096dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 60973320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 60981da177e4SLinus Torvalds 6099a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 6100a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 61011da177e4SLinus Torvalds 6102ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 6103a8cddc5dSJ. Bruce Fields if (status) 6104a8cddc5dSJ. Bruce Fields return status; 61051da177e4SLinus Torvalds 61069072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 6107ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 61083320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 61099072d5c6SJ. Bruce Fields if (status) 61101da177e4SLinus Torvalds goto out; 6111fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 611268b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 611335a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 6114feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 61152585fc79STrond Myklebust goto put_stateid; 611635a92fe8SJeff Layton } 6117dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 61189767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 6119feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6120dd5e3fbcSChuck Lever trace_nfsd_open_confirm(oc->oc_seqid, &stp->st_stid.sc_stateid); 61212a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 612268b66e82SJ. Bruce Fields status = nfs_ok; 61232585fc79STrond Myklebust put_stateid: 61242585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 61251da177e4SLinus Torvalds out: 61269411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 61271da177e4SLinus Torvalds return status; 61281da177e4SLinus Torvalds } 61291da177e4SLinus Torvalds 61306409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 61311da177e4SLinus Torvalds { 613282c5ff1bSJeff Layton if (!test_access(access, stp)) 61336409a5a6SJ. Bruce Fields return; 613411b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 613582c5ff1bSJeff Layton clear_access(access, stp); 6136f197c271SJ. Bruce Fields } 61376409a5a6SJ. Bruce Fields 61386409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 61396409a5a6SJ. Bruce Fields { 61406409a5a6SJ. Bruce Fields switch (to_access) { 61416409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 61426409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 61436409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 61446409a5a6SJ. Bruce Fields break; 61456409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 61466409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 61476409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 61486409a5a6SJ. Bruce Fields break; 61496409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 61506409a5a6SJ. Bruce Fields break; 61516409a5a6SJ. Bruce Fields default: 6152063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 61531da177e4SLinus Torvalds } 61541da177e4SLinus Torvalds } 61551da177e4SLinus Torvalds 6156b37ad28bSAl Viro __be32 6157ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 6158eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 61591da177e4SLinus Torvalds { 6160eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 6161b37ad28bSAl Viro __be32 status; 6162dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 61633320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 61641da177e4SLinus Torvalds 6165a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 6166a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 61671da177e4SLinus Torvalds 6168c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 61692c8bd7e0SBenny Halevy if (od->od_deleg_want) 61702c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 61712c8bd7e0SBenny Halevy od->od_deleg_want); 61721da177e4SLinus Torvalds 6173c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 61743320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 61759072d5c6SJ. Bruce Fields if (status) 61761da177e4SLinus Torvalds goto out; 61771da177e4SLinus Torvalds status = nfserr_inval; 617882c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 6179c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 61801da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 61810667b1e9STrond Myklebust goto put_stateid; 61821da177e4SLinus Torvalds } 6183ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 6184c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 61851da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 61860667b1e9STrond Myklebust goto put_stateid; 61871da177e4SLinus Torvalds } 61886409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 6189ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 61909767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 61911da177e4SLinus Torvalds status = nfs_ok; 61920667b1e9STrond Myklebust put_stateid: 6193feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 61940667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 61951da177e4SLinus Torvalds out: 61969411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 61971da177e4SLinus Torvalds return status; 61981da177e4SLinus Torvalds } 61991da177e4SLinus Torvalds 6200f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 6201f7a4d872SJ. Bruce Fields { 6202acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 6203e8568739SJeff Layton bool unhashed; 6204d83017f9SJeff Layton LIST_HEAD(reaplist); 6205acf9295bSTrond Myklebust 62062c41beb0SJeff Layton spin_lock(&clp->cl_lock); 6207e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 6208acf9295bSTrond Myklebust 6209d83017f9SJeff Layton if (clp->cl_minorversion) { 6210e8568739SJeff Layton if (unhashed) 6211d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 6212d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6213d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6214d83017f9SJeff Layton } else { 6215d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6216d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6217e8568739SJeff Layton if (unhashed) 6218d3134b10SJeff Layton move_to_close_lru(s, clp->net); 621938c387b5SJ. Bruce Fields } 6220d83017f9SJeff Layton } 622138c387b5SJ. Bruce Fields 62221da177e4SLinus Torvalds /* 62231da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 62241da177e4SLinus Torvalds */ 6225b37ad28bSAl Viro __be32 6226ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6227eb69853dSChristoph Hellwig union nfsd4_op_u *u) 62281da177e4SLinus Torvalds { 6229eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 6230b37ad28bSAl Viro __be32 status; 6231dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 62323320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 62333320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 62341da177e4SLinus Torvalds 6235a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 6236a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 62371da177e4SLinus Torvalds 6238f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 6239f7a4d872SJ. Bruce Fields &close->cl_stateid, 6240f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 62413320fef1SStanislav Kinsbursky &stp, nn); 62429411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 62439072d5c6SJ. Bruce Fields if (status) 62441da177e4SLinus Torvalds goto out; 624515ca08d3STrond Myklebust 624615ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 6247bd2decacSJeff Layton 6248bd2decacSJeff Layton /* 6249bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 6250bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 6251bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 6252bd2decacSJeff Layton * that racing ops see that there was a state change. 6253bd2decacSJeff Layton */ 62549767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 62551da177e4SLinus Torvalds 6256f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 625715ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 62588a0b589dSTrond Myklebust 6259bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 6260bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 6261bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 6262bd2decacSJeff Layton * universally. 6263bd2decacSJeff Layton * 6264bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 6265bd2decacSJeff Layton */ 6266bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 6267fb500a7cSTrond Myklebust 62688a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 62698a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 62701da177e4SLinus Torvalds out: 62711da177e4SLinus Torvalds return status; 62721da177e4SLinus Torvalds } 62731da177e4SLinus Torvalds 6274b37ad28bSAl Viro __be32 6275ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6276eb69853dSChristoph Hellwig union nfsd4_op_u *u) 62771da177e4SLinus Torvalds { 6278eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 6279203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 6280203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 628138c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6282b37ad28bSAl Viro __be32 status; 62833320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 62841da177e4SLinus Torvalds 6285ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 6286203a8c8eSJ. Bruce Fields return status; 62871da177e4SLinus Torvalds 62882dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 628938c2f4b1SJ. Bruce Fields if (status) 6290203a8c8eSJ. Bruce Fields goto out; 629138c2f4b1SJ. Bruce Fields dp = delegstateid(s); 629203da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 6293203a8c8eSJ. Bruce Fields if (status) 6294fd911011STrond Myklebust goto put_stateid; 6295203a8c8eSJ. Bruce Fields 62963bd64a5bSJ. Bruce Fields destroy_delegation(dp); 6297fd911011STrond Myklebust put_stateid: 6298fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 62991da177e4SLinus Torvalds out: 63001da177e4SLinus Torvalds return status; 63011da177e4SLinus Torvalds } 63021da177e4SLinus Torvalds 630387df4de8SBenny Halevy static inline u64 630487df4de8SBenny Halevy end_offset(u64 start, u64 len) 630587df4de8SBenny Halevy { 630687df4de8SBenny Halevy u64 end; 630787df4de8SBenny Halevy 630887df4de8SBenny Halevy end = start + len; 630987df4de8SBenny Halevy return end >= start ? end: NFS4_MAX_UINT64; 631087df4de8SBenny Halevy } 631187df4de8SBenny Halevy 631287df4de8SBenny Halevy /* last octet in a range */ 631387df4de8SBenny Halevy static inline u64 631487df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 631587df4de8SBenny Halevy { 631687df4de8SBenny Halevy u64 end; 631787df4de8SBenny Halevy 6318063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 631987df4de8SBenny Halevy end = start + len; 632087df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 632187df4de8SBenny Halevy } 632287df4de8SBenny Halevy 63231da177e4SLinus Torvalds /* 63241da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 63251da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 63261da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 63271da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 63281da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 63291da177e4SLinus Torvalds * the VFS, but this is a very deep change! 63301da177e4SLinus Torvalds */ 63311da177e4SLinus Torvalds static inline void 63321da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 63331da177e4SLinus Torvalds { 63341da177e4SLinus Torvalds if (lock->fl_start < 0) 63351da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 63361da177e4SLinus Torvalds if (lock->fl_end < 0) 63371da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 63381da177e4SLinus Torvalds } 63391da177e4SLinus Torvalds 6340cae80b30SJeff Layton static fl_owner_t 6341cae80b30SJeff Layton nfsd4_fl_get_owner(fl_owner_t owner) 6342aef9583bSKinglong Mee { 6343cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6344cae80b30SJeff Layton 6345cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 6346cae80b30SJeff Layton return owner; 6347aef9583bSKinglong Mee } 6348aef9583bSKinglong Mee 6349cae80b30SJeff Layton static void 6350cae80b30SJeff Layton nfsd4_fl_put_owner(fl_owner_t owner) 6351aef9583bSKinglong Mee { 6352cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6353aef9583bSKinglong Mee 6354cae80b30SJeff Layton if (lo) 6355aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 6356aef9583bSKinglong Mee } 6357aef9583bSKinglong Mee 635876d348faSJeff Layton static void 635976d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 636076d348faSJeff Layton { 636176d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 636276d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 636376d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 636476d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 636576d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 636676d348faSJeff Layton bool queue = false; 636776d348faSJeff Layton 63687919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 63690cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 637076d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 637176d348faSJeff Layton list_del_init(&nbl->nbl_list); 63727919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 637376d348faSJeff Layton queue = true; 637476d348faSJeff Layton } 63750cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 637676d348faSJeff Layton 637776d348faSJeff Layton if (queue) 637876d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 637976d348faSJeff Layton } 638076d348faSJeff Layton 63817b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 638276d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 6383aef9583bSKinglong Mee .lm_get_owner = nfsd4_fl_get_owner, 6384aef9583bSKinglong Mee .lm_put_owner = nfsd4_fl_put_owner, 6385d5b9026aSNeilBrown }; 63861da177e4SLinus Torvalds 63871da177e4SLinus Torvalds static inline void 63881da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 63891da177e4SLinus Torvalds { 6390fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 63911da177e4SLinus Torvalds 6392d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 6393fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 63946f4859b8SJ. Bruce Fields xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner, 63956f4859b8SJ. Bruce Fields GFP_KERNEL); 63967c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 63977c13f344SJ. Bruce Fields /* We just don't care that much */ 63987c13f344SJ. Bruce Fields goto nevermind; 6399fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 6400d5b9026aSNeilBrown } else { 64017c13f344SJ. Bruce Fields nevermind: 64027c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 64037c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 6404d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 6405d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 64061da177e4SLinus Torvalds } 64071da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 640887df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 640987df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 64101da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 64111da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 64121da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 64131da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 64141da177e4SLinus Torvalds } 64151da177e4SLinus Torvalds 6416fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6417c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 64181da177e4SLinus Torvalds { 6419d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 6420b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 64211da177e4SLinus Torvalds 64220a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 64230a880a28STrond Myklebust 6424d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 6425d4f0489fSTrond Myklebust so_strhash) { 6426b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 6427b3c32bcdSTrond Myklebust continue; 6428b5971afaSKinglong Mee if (same_owner_str(so, owner)) 6429b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 64301da177e4SLinus Torvalds } 64311da177e4SLinus Torvalds return NULL; 64321da177e4SLinus Torvalds } 64331da177e4SLinus Torvalds 6434c58c6610STrond Myklebust static struct nfs4_lockowner * 6435c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 6436c58c6610STrond Myklebust { 6437c58c6610STrond Myklebust struct nfs4_lockowner *lo; 6438c58c6610STrond Myklebust 6439d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6440c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 6441d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6442c58c6610STrond Myklebust return lo; 6443c58c6610STrond Myklebust } 6444c58c6610STrond Myklebust 64458f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 64468f4b54c5SJeff Layton { 6447c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 64488f4b54c5SJeff Layton } 64498f4b54c5SJeff Layton 64506b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 64516b180f0bSJeff Layton { 64526b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 64536b180f0bSJeff Layton 64546b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 64556b180f0bSJeff Layton } 64566b180f0bSJeff Layton 64576b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 64588f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 64596b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 64606b180f0bSJeff Layton }; 64616b180f0bSJeff Layton 64621da177e4SLinus Torvalds /* 64631da177e4SLinus Torvalds * Alloc a lock owner structure. 64641da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 646525985edcSLucas De Marchi * occurred. 64661da177e4SLinus Torvalds * 646716bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 64681da177e4SLinus Torvalds */ 6469fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6470c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 6471c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 6472c58c6610STrond Myklebust struct nfsd4_lock *lock) 6473c58c6610STrond Myklebust { 6474c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 64751da177e4SLinus Torvalds 6476fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 6477fe0750e5SJ. Bruce Fields if (!lo) 64781da177e4SLinus Torvalds return NULL; 647976d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 6480fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 6481fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 64825db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 64836b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 6484d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6485c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 6486c58c6610STrond Myklebust if (ret == NULL) { 6487c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 6488d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 6489c58c6610STrond Myklebust ret = lo; 6490c58c6610STrond Myklebust } else 6491d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 6492d50ffdedSKinglong Mee 6493d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6494340f0ba1SJ. Bruce Fields return ret; 64951da177e4SLinus Torvalds } 64961da177e4SLinus Torvalds 6497fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 6498a451b123STrond Myklebust find_lock_stateid(const struct nfs4_lockowner *lo, 6499a451b123STrond Myklebust const struct nfs4_ol_stateid *ost) 6500fd1fd685STrond Myklebust { 6501fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 6502fd1fd685STrond Myklebust 6503a451b123STrond Myklebust lockdep_assert_held(&ost->st_stid.sc_client->cl_lock); 6504fd1fd685STrond Myklebust 6505a451b123STrond Myklebust /* If ost is not hashed, ost->st_locks will not be valid */ 6506a451b123STrond Myklebust if (!nfs4_ol_stateid_unhashed(ost)) 6507a451b123STrond Myklebust list_for_each_entry(lst, &ost->st_locks, st_locks) { 6508a451b123STrond Myklebust if (lst->st_stateowner == &lo->lo_owner) { 6509fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 6510fd1fd685STrond Myklebust return lst; 6511fd1fd685STrond Myklebust } 6512fd1fd685STrond Myklebust } 6513fd1fd685STrond Myklebust return NULL; 6514fd1fd685STrond Myklebust } 6515fd1fd685STrond Myklebust 6516beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 6517356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 6518356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 6519f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 65201da177e4SLinus Torvalds { 6521d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 6522beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 65231da177e4SLinus Torvalds 6524beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 65254f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 6526beeca19cSTrond Myklebust retry: 6527beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 6528a451b123STrond Myklebust if (nfs4_ol_stateid_unhashed(open_stp)) 6529a451b123STrond Myklebust goto out_close; 6530a451b123STrond Myklebust retstp = find_lock_stateid(lo, open_stp); 6531beeca19cSTrond Myklebust if (retstp) 6532a451b123STrond Myklebust goto out_found; 6533a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 65343abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 6535b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 653613cd2184SNeilBrown get_nfs4_file(fp); 653711b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 65380997b173SJ. Bruce Fields stp->st_access_bmap = 0; 65391da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 65404c4cd222SNeilBrown stp->st_openstp = open_stp; 6541a451b123STrond Myklebust spin_lock(&fp->fi_lock); 65423c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 65431c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 65441d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 65451d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 6546beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 6547a451b123STrond Myklebust return stp; 6548a451b123STrond Myklebust out_found: 6549a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 6550beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 6551beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 6552beeca19cSTrond Myklebust goto retry; 6553beeca19cSTrond Myklebust } 6554beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 6555beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 6556a451b123STrond Myklebust return retstp; 6557a451b123STrond Myklebust out_close: 6558a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 6559a451b123STrond Myklebust mutex_unlock(&stp->st_mutex); 6560a451b123STrond Myklebust return NULL; 65611da177e4SLinus Torvalds } 65621da177e4SLinus Torvalds 6563c53530daSJeff Layton static struct nfs4_ol_stateid * 6564356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 6565356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 6566356a95ecSJeff Layton bool *new) 6567356a95ecSJeff Layton { 6568356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 6569356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 6570356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 6571356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 6572356a95ecSJeff Layton 6573beeca19cSTrond Myklebust *new = false; 6574356a95ecSJeff Layton spin_lock(&clp->cl_lock); 6575a451b123STrond Myklebust lst = find_lock_stateid(lo, ost); 6576356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 6577beeca19cSTrond Myklebust if (lst != NULL) { 6578beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 6579beeca19cSTrond Myklebust goto out; 6580beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 6581beeca19cSTrond Myklebust } 6582d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 6583356a95ecSJeff Layton if (ns == NULL) 6584356a95ecSJeff Layton return NULL; 6585356a95ecSJeff Layton 6586beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 6587beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 6588356a95ecSJeff Layton *new = true; 6589beeca19cSTrond Myklebust else 6590356a95ecSJeff Layton nfs4_put_stid(ns); 6591beeca19cSTrond Myklebust out: 6592356a95ecSJeff Layton return lst; 6593356a95ecSJeff Layton } 6594c53530daSJeff Layton 6595fd39ca9aSNeilBrown static int 65961da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 65971da177e4SLinus Torvalds { 659887df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 6599e7969315SKinglong Mee (length > ~offset))); 66001da177e4SLinus Torvalds } 66011da177e4SLinus Torvalds 6602dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 66030997b173SJ. Bruce Fields { 660411b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 66050997b173SJ. Bruce Fields 66067214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 66077214e860SJeff Layton 660882c5ff1bSJeff Layton if (test_access(access, lock_stp)) 66090997b173SJ. Bruce Fields return; 661012659651SJeff Layton __nfs4_file_get_access(fp, access); 661182c5ff1bSJeff Layton set_access(access, lock_stp); 66120997b173SJ. Bruce Fields } 66130997b173SJ. Bruce Fields 6614356a95ecSJeff Layton static __be32 6615356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 6616356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 6617356a95ecSJeff Layton struct nfsd4_lock *lock, 6618dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 661964a284d0SJ. Bruce Fields { 66205db1c03fSJeff Layton __be32 status; 662111b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 662264a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 662364a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 66242b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 662564a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 6626dd257933SJeff Layton struct nfs4_ol_stateid *lst; 662764a284d0SJ. Bruce Fields unsigned int strhashval; 662864a284d0SJ. Bruce Fields 6629c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 6630c53530daSJeff Layton if (!lo) { 663176f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 663264a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 663364a284d0SJ. Bruce Fields if (lo == NULL) 663464a284d0SJ. Bruce Fields return nfserr_jukebox; 6635c53530daSJeff Layton } else { 6636c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 66375db1c03fSJeff Layton status = nfserr_bad_seqid; 6638c53530daSJeff Layton if (!cstate->minorversion && 6639c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 66405db1c03fSJeff Layton goto out; 6641c53530daSJeff Layton } 6642c53530daSJeff Layton 6643dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 6644dd257933SJeff Layton if (lst == NULL) { 66455db1c03fSJeff Layton status = nfserr_jukebox; 66465db1c03fSJeff Layton goto out; 664764a284d0SJ. Bruce Fields } 6648dd257933SJeff Layton 66495db1c03fSJeff Layton status = nfs_ok; 6650dd257933SJeff Layton *plst = lst; 66515db1c03fSJeff Layton out: 66525db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 66535db1c03fSJeff Layton return status; 665464a284d0SJ. Bruce Fields } 665564a284d0SJ. Bruce Fields 66561da177e4SLinus Torvalds /* 66571da177e4SLinus Torvalds * LOCK operation 66581da177e4SLinus Torvalds */ 6659b37ad28bSAl Viro __be32 6660ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6661eb69853dSChristoph Hellwig union nfsd4_op_u *u) 66621da177e4SLinus Torvalds { 6663eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 6664fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 6665fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 66663d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 66670667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 66687214e860SJeff Layton struct nfs4_file *fp; 6669eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 667076d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 667121179d81SJeff Layton struct file_lock *file_lock = NULL; 667221179d81SJeff Layton struct file_lock *conflock = NULL; 6673b37ad28bSAl Viro __be32 status = 0; 6674b34f27aaSJ. Bruce Fields int lkflg; 6675b8dd7b9aSAl Viro int err; 66765db1c03fSJeff Layton bool new = false; 667776d348faSJeff Layton unsigned char fl_type; 667876d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 66793320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 66803320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 66811da177e4SLinus Torvalds 66821da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 66831da177e4SLinus Torvalds (long long) lock->lk_offset, 66841da177e4SLinus Torvalds (long long) lock->lk_length); 66851da177e4SLinus Torvalds 66861da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 66871da177e4SLinus Torvalds return nfserr_inval; 66881da177e4SLinus Torvalds 6689ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 66908837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 6691a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 6692a6f6ef2fSAndy Adamson return status; 6693a6f6ef2fSAndy Adamson } 6694a6f6ef2fSAndy Adamson 66951da177e4SLinus Torvalds if (lock->lk_is_new) { 6696684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 6697684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 669876f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 6699684e5638SJ. Bruce Fields &cstate->session->se_client->cl_clientid, 6700684e5638SJ. Bruce Fields sizeof(clientid_t)); 6701684e5638SJ. Bruce Fields 67021da177e4SLinus Torvalds status = nfserr_stale_clientid; 67032c142baaSStanislav Kinsbursky if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) 67041da177e4SLinus Torvalds goto out; 67051da177e4SLinus Torvalds 67061da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 6707c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 67081da177e4SLinus Torvalds lock->lk_new_open_seqid, 67091da177e4SLinus Torvalds &lock->lk_new_open_stateid, 67103320fef1SStanislav Kinsbursky &open_stp, nn); 671137515177SNeilBrown if (status) 67121da177e4SLinus Torvalds goto out; 6713feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 6714fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 6715b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 6716684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 671776f6c9e1SKinglong Mee &lock->lk_new_clientid)) 6718b34f27aaSJ. Bruce Fields goto out; 671964a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 67205db1c03fSJeff Layton &lock_stp, &new); 67213d0fabd5STrond Myklebust } else { 6722dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 67231da177e4SLinus Torvalds lock->lk_old_lock_seqid, 67241da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 67253320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 67263d0fabd5STrond Myklebust } 67271da177e4SLinus Torvalds if (status) 67281da177e4SLinus Torvalds goto out; 6729fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 67301da177e4SLinus Torvalds 6731b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 6732b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 6733b34f27aaSJ. Bruce Fields if (status) 6734b34f27aaSJ. Bruce Fields goto out; 6735b34f27aaSJ. Bruce Fields 67360dd395dcSNeilBrown status = nfserr_grace; 67373320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 67380dd395dcSNeilBrown goto out; 67390dd395dcSNeilBrown status = nfserr_no_grace; 67403320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 67410dd395dcSNeilBrown goto out; 67420dd395dcSNeilBrown 674311b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 67441da177e4SLinus Torvalds switch (lock->lk_type) { 67451da177e4SLinus Torvalds case NFS4_READW_LT: 674676d348faSJeff Layton if (nfsd4_has_session(cstate)) 674776d348faSJeff Layton fl_flags |= FL_SLEEP; 6748df561f66SGustavo A. R. Silva fallthrough; 674976d348faSJeff Layton case NFS4_READ_LT: 67507214e860SJeff Layton spin_lock(&fp->fi_lock); 6751eb82dd39SJeff Layton nf = find_readable_file_locked(fp); 6752eb82dd39SJeff Layton if (nf) 67530997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 67547214e860SJeff Layton spin_unlock(&fp->fi_lock); 675576d348faSJeff Layton fl_type = F_RDLCK; 67561da177e4SLinus Torvalds break; 67571da177e4SLinus Torvalds case NFS4_WRITEW_LT: 675876d348faSJeff Layton if (nfsd4_has_session(cstate)) 675976d348faSJeff Layton fl_flags |= FL_SLEEP; 6760df561f66SGustavo A. R. Silva fallthrough; 676176d348faSJeff Layton case NFS4_WRITE_LT: 67627214e860SJeff Layton spin_lock(&fp->fi_lock); 6763eb82dd39SJeff Layton nf = find_writeable_file_locked(fp); 6764eb82dd39SJeff Layton if (nf) 67650997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 67667214e860SJeff Layton spin_unlock(&fp->fi_lock); 676776d348faSJeff Layton fl_type = F_WRLCK; 67681da177e4SLinus Torvalds break; 67691da177e4SLinus Torvalds default: 67701da177e4SLinus Torvalds status = nfserr_inval; 67711da177e4SLinus Torvalds goto out; 67721da177e4SLinus Torvalds } 677376d348faSJeff Layton 6774eb82dd39SJeff Layton if (!nf) { 6775f9d7562fSJ. Bruce Fields status = nfserr_openmode; 6776f9d7562fSJ. Bruce Fields goto out; 6777f9d7562fSJ. Bruce Fields } 6778aef9583bSKinglong Mee 677976d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 678076d348faSJeff Layton if (!nbl) { 678176d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 678276d348faSJeff Layton status = nfserr_jukebox; 678376d348faSJeff Layton goto out; 678476d348faSJeff Layton } 678576d348faSJeff Layton 678676d348faSJeff Layton file_lock = &nbl->nbl_lock; 678776d348faSJeff Layton file_lock->fl_type = fl_type; 6788aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 678921179d81SJeff Layton file_lock->fl_pid = current->tgid; 6790eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 679176d348faSJeff Layton file_lock->fl_flags = fl_flags; 679221179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 679321179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 679421179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 679521179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 67961da177e4SLinus Torvalds 679721179d81SJeff Layton conflock = locks_alloc_lock(); 679821179d81SJeff Layton if (!conflock) { 679921179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 680021179d81SJeff Layton status = nfserr_jukebox; 680121179d81SJeff Layton goto out; 680221179d81SJeff Layton } 68031da177e4SLinus Torvalds 680476d348faSJeff Layton if (fl_flags & FL_SLEEP) { 680520b7d86fSArnd Bergmann nbl->nbl_time = ktime_get_boottime_seconds(); 68060cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 680776d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 68087919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 68090cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 681076d348faSJeff Layton } 681176d348faSJeff Layton 6812eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, conflock); 681376d348faSJeff Layton switch (err) { 68141da177e4SLinus Torvalds case 0: /* success! */ 68159767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 6816b8dd7b9aSAl Viro status = 0; 681703f318caSJ. Bruce Fields if (lock->lk_reclaim) 681803f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 6819eb76b3fdSAndy Adamson break; 682076d348faSJeff Layton case FILE_LOCK_DEFERRED: 682176d348faSJeff Layton nbl = NULL; 6822df561f66SGustavo A. R. Silva fallthrough; 682376d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 6824eb76b3fdSAndy Adamson status = nfserr_denied; 6825eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 682621179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 6827eb76b3fdSAndy Adamson break; 682876d348faSJeff Layton case -EDEADLK: 68291da177e4SLinus Torvalds status = nfserr_deadlock; 6830eb76b3fdSAndy Adamson break; 68311da177e4SLinus Torvalds default: 6832fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 68333e772463SJ. Bruce Fields status = nfserrno(err); 6834eb76b3fdSAndy Adamson break; 68351da177e4SLinus Torvalds } 68361da177e4SLinus Torvalds out: 683776d348faSJeff Layton if (nbl) { 683876d348faSJeff Layton /* dequeue it if we queued it before */ 683976d348faSJeff Layton if (fl_flags & FL_SLEEP) { 68400cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 684176d348faSJeff Layton list_del_init(&nbl->nbl_list); 68427919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 68430cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 684476d348faSJeff Layton } 684576d348faSJeff Layton free_blocked_lock(nbl); 684676d348faSJeff Layton } 6847eb82dd39SJeff Layton if (nf) 6848eb82dd39SJeff Layton nfsd_file_put(nf); 68495db1c03fSJeff Layton if (lock_stp) { 68505db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 68515db1c03fSJeff Layton if (cstate->replay_owner && 68525db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 68535db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 68545db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 68555db1c03fSJeff Layton 68565db1c03fSJeff Layton /* 68575db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 68585db1c03fSJeff Layton * returning an error, then just go ahead and release it. 68595db1c03fSJeff Layton */ 686025020720SJ. Bruce Fields if (status && new) 68615db1c03fSJeff Layton release_lock_stateid(lock_stp); 6862beeca19cSTrond Myklebust 6863beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 68645db1c03fSJeff Layton 68653d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 68665db1c03fSJeff Layton } 68670667b1e9STrond Myklebust if (open_stp) 68680667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 68699411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 687021179d81SJeff Layton if (conflock) 687121179d81SJeff Layton locks_free_lock(conflock); 68721da177e4SLinus Torvalds return status; 68731da177e4SLinus Torvalds } 68741da177e4SLinus Torvalds 68751da177e4SLinus Torvalds /* 687655ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 687755ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 687855ef1274SJ. Bruce Fields * vfs_test_lock. (Arguably perhaps test_lock should be done with an 687955ef1274SJ. Bruce Fields * inode operation.) 688055ef1274SJ. Bruce Fields */ 688104da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 688255ef1274SJ. Bruce Fields { 68836b556ca2SJeff Layton struct nfsd_file *nf; 68846b556ca2SJeff Layton __be32 err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); 688504da6e9dSAl Viro if (!err) { 68866b556ca2SJeff Layton err = nfserrno(vfs_test_lock(nf->nf_file, lock)); 68876b556ca2SJeff Layton nfsd_file_put(nf); 688804da6e9dSAl Viro } 688955ef1274SJ. Bruce Fields return err; 689055ef1274SJ. Bruce Fields } 689155ef1274SJ. Bruce Fields 689255ef1274SJ. Bruce Fields /* 68931da177e4SLinus Torvalds * LOCKT operation 68941da177e4SLinus Torvalds */ 6895b37ad28bSAl Viro __be32 6896ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6897eb69853dSChristoph Hellwig union nfsd4_op_u *u) 68981da177e4SLinus Torvalds { 6899eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 690021179d81SJeff Layton struct file_lock *file_lock = NULL; 69015db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 6902b37ad28bSAl Viro __be32 status; 69037f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 69041da177e4SLinus Torvalds 69055ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 69061da177e4SLinus Torvalds return nfserr_grace; 69071da177e4SLinus Torvalds 69081da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 69091da177e4SLinus Torvalds return nfserr_inval; 69101da177e4SLinus Torvalds 69119b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 6912b7342204SOlga Kornievskaia status = lookup_clientid(&lockt->lt_clientid, cstate, nn, 6913b7342204SOlga Kornievskaia false); 69149b2ef62bSJ. Bruce Fields if (status) 69151da177e4SLinus Torvalds goto out; 69169b2ef62bSJ. Bruce Fields } 69171da177e4SLinus Torvalds 691875c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 69191da177e4SLinus Torvalds goto out; 69201da177e4SLinus Torvalds 692121179d81SJeff Layton file_lock = locks_alloc_lock(); 692221179d81SJeff Layton if (!file_lock) { 692321179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 692421179d81SJeff Layton status = nfserr_jukebox; 692521179d81SJeff Layton goto out; 692621179d81SJeff Layton } 69276cd90662SKinglong Mee 69281da177e4SLinus Torvalds switch (lockt->lt_type) { 69291da177e4SLinus Torvalds case NFS4_READ_LT: 69301da177e4SLinus Torvalds case NFS4_READW_LT: 693121179d81SJeff Layton file_lock->fl_type = F_RDLCK; 69321da177e4SLinus Torvalds break; 69331da177e4SLinus Torvalds case NFS4_WRITE_LT: 69341da177e4SLinus Torvalds case NFS4_WRITEW_LT: 693521179d81SJeff Layton file_lock->fl_type = F_WRLCK; 69361da177e4SLinus Torvalds break; 69371da177e4SLinus Torvalds default: 69382fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 69391da177e4SLinus Torvalds status = nfserr_inval; 69401da177e4SLinus Torvalds goto out; 69411da177e4SLinus Torvalds } 69421da177e4SLinus Torvalds 6943c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 6944fe0750e5SJ. Bruce Fields if (lo) 694521179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 694621179d81SJeff Layton file_lock->fl_pid = current->tgid; 694721179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 69481da177e4SLinus Torvalds 694921179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 695021179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 69511da177e4SLinus Torvalds 695221179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 69531da177e4SLinus Torvalds 695421179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 695504da6e9dSAl Viro if (status) 6956fd85b817SMarc Eshel goto out; 695704da6e9dSAl Viro 695821179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 69591da177e4SLinus Torvalds status = nfserr_denied; 696021179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 69611da177e4SLinus Torvalds } 69621da177e4SLinus Torvalds out: 69635db1c03fSJeff Layton if (lo) 69645db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 696521179d81SJeff Layton if (file_lock) 696621179d81SJeff Layton locks_free_lock(file_lock); 69671da177e4SLinus Torvalds return status; 69681da177e4SLinus Torvalds } 69691da177e4SLinus Torvalds 6970b37ad28bSAl Viro __be32 6971ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6972eb69853dSChristoph Hellwig union nfsd4_op_u *u) 69731da177e4SLinus Torvalds { 6974eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 6975dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 6976eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 697721179d81SJeff Layton struct file_lock *file_lock = NULL; 6978b37ad28bSAl Viro __be32 status; 6979b8dd7b9aSAl Viro int err; 69803320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 69811da177e4SLinus Torvalds 69821da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 69831da177e4SLinus Torvalds (long long) locku->lu_offset, 69841da177e4SLinus Torvalds (long long) locku->lu_length); 69851da177e4SLinus Torvalds 69861da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 69871da177e4SLinus Torvalds return nfserr_inval; 69881da177e4SLinus Torvalds 69899072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 69903320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 69913320fef1SStanislav Kinsbursky &stp, nn); 69929072d5c6SJ. Bruce Fields if (status) 69931da177e4SLinus Torvalds goto out; 6994eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 6995eb82dd39SJeff Layton if (!nf) { 6996f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 6997858cc573STrond Myklebust goto put_stateid; 6998f9d7562fSJ. Bruce Fields } 699921179d81SJeff Layton file_lock = locks_alloc_lock(); 700021179d81SJeff Layton if (!file_lock) { 700121179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 700221179d81SJeff Layton status = nfserr_jukebox; 7003eb82dd39SJeff Layton goto put_file; 700421179d81SJeff Layton } 70056cd90662SKinglong Mee 700621179d81SJeff Layton file_lock->fl_type = F_UNLCK; 7007aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 700821179d81SJeff Layton file_lock->fl_pid = current->tgid; 7009eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 701021179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 701121179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 701221179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 70131da177e4SLinus Torvalds 701421179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 701521179d81SJeff Layton locku->lu_length); 701621179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 70171da177e4SLinus Torvalds 7018eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, NULL); 7019b8dd7b9aSAl Viro if (err) { 7020fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 70211da177e4SLinus Torvalds goto out_nfserr; 70221da177e4SLinus Torvalds } 70239767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 7024eb82dd39SJeff Layton put_file: 7025eb82dd39SJeff Layton nfsd_file_put(nf); 7026858cc573STrond Myklebust put_stateid: 7027feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 7028858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 70291da177e4SLinus Torvalds out: 70309411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 703121179d81SJeff Layton if (file_lock) 703221179d81SJeff Layton locks_free_lock(file_lock); 70331da177e4SLinus Torvalds return status; 70341da177e4SLinus Torvalds 70351da177e4SLinus Torvalds out_nfserr: 7036b8dd7b9aSAl Viro status = nfserrno(err); 7037eb82dd39SJeff Layton goto put_file; 70381da177e4SLinus Torvalds } 70391da177e4SLinus Torvalds 70401da177e4SLinus Torvalds /* 70411da177e4SLinus Torvalds * returns 7042f9c00c3aSJeff Layton * true: locks held by lockowner 7043f9c00c3aSJeff Layton * false: no locks held by lockowner 70441da177e4SLinus Torvalds */ 7045f9c00c3aSJeff Layton static bool 7046f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 70471da177e4SLinus Torvalds { 7048bd61e0a9SJeff Layton struct file_lock *fl; 7049f9c00c3aSJeff Layton int status = false; 7050eb82dd39SJeff Layton struct nfsd_file *nf = find_any_file(fp); 7051f9c00c3aSJeff Layton struct inode *inode; 7052bd61e0a9SJeff Layton struct file_lock_context *flctx; 7053f9c00c3aSJeff Layton 7054eb82dd39SJeff Layton if (!nf) { 7055f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 7056f9c00c3aSJeff Layton WARN_ON_ONCE(1); 7057f9c00c3aSJeff Layton return status; 7058f9c00c3aSJeff Layton } 7059f9c00c3aSJeff Layton 7060eb82dd39SJeff Layton inode = locks_inode(nf->nf_file); 7061bd61e0a9SJeff Layton flctx = inode->i_flctx; 70621da177e4SLinus Torvalds 7063bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 70646109c850SJeff Layton spin_lock(&flctx->flc_lock); 7065bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 7066bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 7067f9c00c3aSJeff Layton status = true; 7068f9c00c3aSJeff Layton break; 70691da177e4SLinus Torvalds } 7070796dadfdSJ. Bruce Fields } 70716109c850SJeff Layton spin_unlock(&flctx->flc_lock); 7072bd61e0a9SJeff Layton } 7073eb82dd39SJeff Layton nfsd_file_put(nf); 70741da177e4SLinus Torvalds return status; 70751da177e4SLinus Torvalds } 70761da177e4SLinus Torvalds 7077b37ad28bSAl Viro __be32 7078b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 7079b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 7080eb69853dSChristoph Hellwig union nfsd4_op_u *u) 70811da177e4SLinus Torvalds { 7082eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 70831da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 7084882e9d25SJeff Layton struct nfs4_stateowner *sop; 7085882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 7086dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 70871da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 7088d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 7089b37ad28bSAl Viro __be32 status; 70907f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 7091c58c6610STrond Myklebust struct nfs4_client *clp; 709288584818SChuck Lever LIST_HEAD (reaplist); 70931da177e4SLinus Torvalds 70941da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 70951da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 70961da177e4SLinus Torvalds 7097b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 70989b2ef62bSJ. Bruce Fields if (status) 709951f5e783STrond Myklebust return status; 71009b2ef62bSJ. Bruce Fields 7101d4f0489fSTrond Myklebust clp = cstate->clp; 7102fd44907cSJeff Layton /* Find the matching lock stateowner */ 7103d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7104882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 7105d4f0489fSTrond Myklebust so_strhash) { 7106882e9d25SJeff Layton 7107882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 710816bfdaafSJ. Bruce Fields continue; 7109882e9d25SJeff Layton 7110882e9d25SJeff Layton /* see if there are still any locks associated with it */ 7111882e9d25SJeff Layton lo = lockowner(sop); 7112882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 7113882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 7114882e9d25SJeff Layton status = nfserr_locks_held; 7115882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 711651f5e783STrond Myklebust return status; 7117882e9d25SJeff Layton } 7118882e9d25SJeff Layton } 7119882e9d25SJeff Layton 7120b5971afaSKinglong Mee nfs4_get_stateowner(sop); 7121fd44907cSJeff Layton break; 7122fd44907cSJeff Layton } 712388584818SChuck Lever if (!lo) { 7124d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 712588584818SChuck Lever return status; 712688584818SChuck Lever } 712788584818SChuck Lever 712888584818SChuck Lever unhash_lockowner_locked(lo); 712988584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 713088584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 713188584818SChuck Lever struct nfs4_ol_stateid, 713288584818SChuck Lever st_perstateowner); 713388584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 713488584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 713588584818SChuck Lever } 713688584818SChuck Lever spin_unlock(&clp->cl_lock); 713788584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 713868ef3bc3SJeff Layton remove_blocked_locks(lo); 713988584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 714088584818SChuck Lever 71411da177e4SLinus Torvalds return status; 71421da177e4SLinus Torvalds } 71431da177e4SLinus Torvalds 71441da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 7145a55370a3SNeilBrown alloc_reclaim(void) 71461da177e4SLinus Torvalds { 7147a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 71481da177e4SLinus Torvalds } 71491da177e4SLinus Torvalds 71500ce0c2b5SJeff Layton bool 71516b189105SScott Mayhew nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) 7152c7b9a459SNeilBrown { 71530ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 7154c7b9a459SNeilBrown 715552e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 71560ce0c2b5SJeff Layton return (crp && crp->cr_clp); 7157c7b9a459SNeilBrown } 7158c7b9a459SNeilBrown 71591da177e4SLinus Torvalds /* 71601da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 71616b189105SScott Mayhew * 71626b189105SScott Mayhew * The caller is responsible for freeing name.data if NULL is returned (it 71636b189105SScott Mayhew * will be freed in nfs4_remove_reclaim_record in the normal case). 71641da177e4SLinus Torvalds */ 7165772a9bbbSJeff Layton struct nfs4_client_reclaim * 71666ee95d1cSScott Mayhew nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, 71676ee95d1cSScott Mayhew struct nfsd_net *nn) 71681da177e4SLinus Torvalds { 71691da177e4SLinus Torvalds unsigned int strhashval; 7170772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 71711da177e4SLinus Torvalds 7172dd5e3fbcSChuck Lever trace_nfsd_clid_reclaim(nn, name.len, name.data); 7173a55370a3SNeilBrown crp = alloc_reclaim(); 7174772a9bbbSJeff Layton if (crp) { 7175a55370a3SNeilBrown strhashval = clientstr_hashval(name); 71761da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 717752e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 71786b189105SScott Mayhew crp->cr_name.data = name.data; 71796b189105SScott Mayhew crp->cr_name.len = name.len; 71806ee95d1cSScott Mayhew crp->cr_princhash.data = princhash.data; 71816ee95d1cSScott Mayhew crp->cr_princhash.len = princhash.len; 71820ce0c2b5SJeff Layton crp->cr_clp = NULL; 718352e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 7184772a9bbbSJeff Layton } 7185772a9bbbSJeff Layton return crp; 71861da177e4SLinus Torvalds } 71871da177e4SLinus Torvalds 71882a4317c5SJeff Layton void 718952e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 7190ce30e539SJeff Layton { 7191ce30e539SJeff Layton list_del(&crp->cr_strhash); 71926b189105SScott Mayhew kfree(crp->cr_name.data); 71936ee95d1cSScott Mayhew kfree(crp->cr_princhash.data); 7194ce30e539SJeff Layton kfree(crp); 719552e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 7196ce30e539SJeff Layton } 7197ce30e539SJeff Layton 7198ce30e539SJeff Layton void 719952e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 72001da177e4SLinus Torvalds { 72011da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 72021da177e4SLinus Torvalds int i; 72031da177e4SLinus Torvalds 72041da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 720552e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 720652e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 72071da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 720852e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 72091da177e4SLinus Torvalds } 72101da177e4SLinus Torvalds } 7211063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 72121da177e4SLinus Torvalds } 72131da177e4SLinus Torvalds 72141da177e4SLinus Torvalds /* 72151da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 72162a4317c5SJeff Layton struct nfs4_client_reclaim * 72176b189105SScott Mayhew nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) 72181da177e4SLinus Torvalds { 72191da177e4SLinus Torvalds unsigned int strhashval; 72201da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 72211da177e4SLinus Torvalds 7222dd5e3fbcSChuck Lever trace_nfsd_clid_find(nn, name.len, name.data); 72231da177e4SLinus Torvalds 72246b189105SScott Mayhew strhashval = clientstr_hashval(name); 722552e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 72266b189105SScott Mayhew if (compare_blob(&crp->cr_name, &name) == 0) { 72271da177e4SLinus Torvalds return crp; 72281da177e4SLinus Torvalds } 72291da177e4SLinus Torvalds } 72301da177e4SLinus Torvalds return NULL; 72311da177e4SLinus Torvalds } 72321da177e4SLinus Torvalds 72331da177e4SLinus Torvalds /* 72341da177e4SLinus Torvalds * Called from OPEN. Look for clientid in reclaim list. 72351da177e4SLinus Torvalds */ 7236b37ad28bSAl Viro __be32 72370fe492dbSTrond Myklebust nfs4_check_open_reclaim(clientid_t *clid, 72380fe492dbSTrond Myklebust struct nfsd4_compound_state *cstate, 72390fe492dbSTrond Myklebust struct nfsd_net *nn) 72401da177e4SLinus Torvalds { 72410fe492dbSTrond Myklebust __be32 status; 7242a52d726bSJeff Layton 7243a52d726bSJeff Layton /* find clientid in conf_id_hashtbl */ 7244b7342204SOlga Kornievskaia status = lookup_clientid(clid, cstate, nn, false); 72450fe492dbSTrond Myklebust if (status) 7246a52d726bSJeff Layton return nfserr_reclaim_bad; 7247a52d726bSJeff Layton 72483b3e7b72SJeff Layton if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) 72493b3e7b72SJeff Layton return nfserr_no_grace; 72503b3e7b72SJeff Layton 72510fe492dbSTrond Myklebust if (nfsd4_client_record_check(cstate->clp)) 72520fe492dbSTrond Myklebust return nfserr_reclaim_bad; 72530fe492dbSTrond Myklebust 72540fe492dbSTrond Myklebust return nfs_ok; 72551da177e4SLinus Torvalds } 72561da177e4SLinus Torvalds 7257c2f1a551SMeelap Shah /* 7258c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 7259c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 7260c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 7261c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 7262c2f1a551SMeelap Shah * 7263c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 7264c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 7265c2f1a551SMeelap Shah */ 7266c2f1a551SMeelap Shah static void 7267c2f1a551SMeelap Shah set_max_delegations(void) 7268c2f1a551SMeelap Shah { 7269c2f1a551SMeelap Shah /* 7270c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 7271c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 7272c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 7273c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 7274c2f1a551SMeelap Shah */ 7275c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 7276c2f1a551SMeelap Shah } 7277c2f1a551SMeelap Shah 7278d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 72798daae4dcSStanislav Kinsbursky { 72808daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 72818daae4dcSStanislav Kinsbursky int i; 72828daae4dcSStanislav Kinsbursky 72836da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 72846da2ec56SKees Cook sizeof(struct list_head), 72856da2ec56SKees Cook GFP_KERNEL); 72868daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 7287382a62e7SStanislav Kinsbursky goto err; 72886da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 72896da2ec56SKees Cook sizeof(struct list_head), 72906da2ec56SKees Cook GFP_KERNEL); 72910a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 72920a7ec377SStanislav Kinsbursky goto err_unconf_id; 72936da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 72946da2ec56SKees Cook sizeof(struct list_head), 72956da2ec56SKees Cook GFP_KERNEL); 72961872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 72971872de0eSStanislav Kinsbursky goto err_sessionid; 72988daae4dcSStanislav Kinsbursky 7299382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 73008daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 73010a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 7302382a62e7SStanislav Kinsbursky } 73031872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 73041872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 7305382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 7306a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 73079cc76801SArnd Bergmann nn->boot_time = ktime_get_real_seconds(); 730881833de1SVasily Averin nn->grace_ended = false; 730981833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 731081833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 73115ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 731273758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 7313e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 7314c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 7315e0639dc5SOlga Kornievskaia spin_lock_init(&nn->s2s_cp_lock); 7316e0639dc5SOlga Kornievskaia idr_init(&nn->s2s_cp_stateids); 73178daae4dcSStanislav Kinsbursky 73180cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 73190cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 73200cc11a61SJeff Layton 732109121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 7322d85ed443SStanislav Kinsbursky get_net(net); 732309121281SStanislav Kinsbursky 73248daae4dcSStanislav Kinsbursky return 0; 7325382a62e7SStanislav Kinsbursky 73261872de0eSStanislav Kinsbursky err_sessionid: 73279b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 73280a7ec377SStanislav Kinsbursky err_unconf_id: 73290a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 7330382a62e7SStanislav Kinsbursky err: 7331382a62e7SStanislav Kinsbursky return -ENOMEM; 73328daae4dcSStanislav Kinsbursky } 73338daae4dcSStanislav Kinsbursky 73348daae4dcSStanislav Kinsbursky static void 73354dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 73368daae4dcSStanislav Kinsbursky { 73378daae4dcSStanislav Kinsbursky int i; 73388daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 73398daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 73408daae4dcSStanislav Kinsbursky 73418daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 73428daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 73438daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 73448daae4dcSStanislav Kinsbursky destroy_client(clp); 73458daae4dcSStanislav Kinsbursky } 73468daae4dcSStanislav Kinsbursky } 7347a99454aaSStanislav Kinsbursky 734868ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 734968ef3bc3SJeff Layton 73502b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 73512b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 73522b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 7353a99454aaSStanislav Kinsbursky destroy_client(clp); 7354a99454aaSStanislav Kinsbursky } 73552b905635SKinglong Mee } 7356a99454aaSStanislav Kinsbursky 73571872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 73580a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 73598daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 73604dce0ac9SStanislav Kinsbursky put_net(net); 73618daae4dcSStanislav Kinsbursky } 73628daae4dcSStanislav Kinsbursky 7363f252bc68SStanislav Kinsbursky int 7364d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 7365ac4d8ff2SNeilBrown { 73665e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 7367b5a1a81eSJ. Bruce Fields int ret; 7368b5a1a81eSJ. Bruce Fields 7369681370f4SJ. Bruce Fields ret = get_nfsdfs(net); 73708daae4dcSStanislav Kinsbursky if (ret) 73718daae4dcSStanislav Kinsbursky return ret; 7372681370f4SJ. Bruce Fields ret = nfs4_state_create_net(net); 7373681370f4SJ. Bruce Fields if (ret) { 7374681370f4SJ. Bruce Fields mntput(nn->nfsd_mnt); 7375681370f4SJ. Bruce Fields return ret; 7376681370f4SJ. Bruce Fields } 7377d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 7378d4318acdSJeff Layton nfsd4_client_tracking_init(net); 7379362063a5SScott Mayhew if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) 7380362063a5SScott Mayhew goto skip_grace; 738120b7d86fSArnd Bergmann printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", 73827e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 7383dd5e3fbcSChuck Lever trace_nfsd_grace_start(nn); 73845284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 7385d85ed443SStanislav Kinsbursky return 0; 7386362063a5SScott Mayhew 7387362063a5SScott Mayhew skip_grace: 7388362063a5SScott Mayhew printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n", 7389362063a5SScott Mayhew net->ns.inum); 7390362063a5SScott Mayhew queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ); 7391362063a5SScott Mayhew nfsd4_end_grace(nn); 7392362063a5SScott Mayhew return 0; 7393a6d6b781SJeff Layton } 7394d85ed443SStanislav Kinsbursky 7395d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 7396d85ed443SStanislav Kinsbursky 7397d85ed443SStanislav Kinsbursky int 7398d85ed443SStanislav Kinsbursky nfs4_state_start(void) 7399d85ed443SStanislav Kinsbursky { 7400d85ed443SStanislav Kinsbursky int ret; 7401d85ed443SStanislav Kinsbursky 740251a54568SJeff Layton laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 7403a6d6b781SJeff Layton if (laundry_wq == NULL) { 7404a6d6b781SJeff Layton ret = -ENOMEM; 7405a26dd64fSChuck Lever goto out; 7406a6d6b781SJeff Layton } 7407b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 7408b5a1a81eSJ. Bruce Fields if (ret) 7409b5a1a81eSJ. Bruce Fields goto out_free_laundry; 741009121281SStanislav Kinsbursky 7411c2f1a551SMeelap Shah set_max_delegations(); 7412b5a1a81eSJ. Bruce Fields return 0; 7413d85ed443SStanislav Kinsbursky 7414b5a1a81eSJ. Bruce Fields out_free_laundry: 7415b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 7416a26dd64fSChuck Lever out: 7417b5a1a81eSJ. Bruce Fields return ret; 74181da177e4SLinus Torvalds } 74191da177e4SLinus Torvalds 7420f252bc68SStanislav Kinsbursky void 74214dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 74221da177e4SLinus Torvalds { 74231da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 74241da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 74254dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 74261da177e4SLinus Torvalds 74274dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 74284dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 7429ac55fdc4SJeff Layton 74301da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 7431cdc97505SBenny Halevy spin_lock(&state_lock); 7432e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 74331da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 74343fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 743542690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 74361da177e4SLinus Torvalds } 7437cdc97505SBenny Halevy spin_unlock(&state_lock); 74381da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 74391da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 744042690676SJeff Layton list_del_init(&dp->dl_recall_lru); 74410af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 74421da177e4SLinus Torvalds } 74431da177e4SLinus Torvalds 74443320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 74454dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 7446681370f4SJ. Bruce Fields mntput(nn->nfsd_mnt); 74471da177e4SLinus Torvalds } 74481da177e4SLinus Torvalds 74491da177e4SLinus Torvalds void 74501da177e4SLinus Torvalds nfs4_state_shutdown(void) 74511da177e4SLinus Torvalds { 74525e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 7453c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 74541da177e4SLinus Torvalds } 74558b70484cSTigran Mkrtchyan 74568b70484cSTigran Mkrtchyan static void 74578b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 74588b70484cSTigran Mkrtchyan { 745951100d2bSOlga Kornievskaia if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) && 746051100d2bSOlga Kornievskaia CURRENT_STATEID(stateid)) 746137c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 74628b70484cSTigran Mkrtchyan } 74638b70484cSTigran Mkrtchyan 74648b70484cSTigran Mkrtchyan static void 74658b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 74668b70484cSTigran Mkrtchyan { 746737c593c5STigran Mkrtchyan if (cstate->minorversion) { 746837c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 746951100d2bSOlga Kornievskaia SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 747037c593c5STigran Mkrtchyan } 747137c593c5STigran Mkrtchyan } 747237c593c5STigran Mkrtchyan 747337c593c5STigran Mkrtchyan void 747437c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 747537c593c5STigran Mkrtchyan { 747651100d2bSOlga Kornievskaia CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 74778b70484cSTigran Mkrtchyan } 74788b70484cSTigran Mkrtchyan 747962cd4a59STigran Mkrtchyan /* 748062cd4a59STigran Mkrtchyan * functions to set current state id 748162cd4a59STigran Mkrtchyan */ 74828b70484cSTigran Mkrtchyan void 7483b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 7484b60e9859SChristoph Hellwig union nfsd4_op_u *u) 74859428fe1aSTigran Mkrtchyan { 7486b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 74879428fe1aSTigran Mkrtchyan } 74889428fe1aSTigran Mkrtchyan 74899428fe1aSTigran Mkrtchyan void 7490b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 7491b60e9859SChristoph Hellwig union nfsd4_op_u *u) 74928b70484cSTigran Mkrtchyan { 7493b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 74948b70484cSTigran Mkrtchyan } 74958b70484cSTigran Mkrtchyan 74968b70484cSTigran Mkrtchyan void 7497b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 7498b60e9859SChristoph Hellwig union nfsd4_op_u *u) 749962cd4a59STigran Mkrtchyan { 7500b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 750162cd4a59STigran Mkrtchyan } 750262cd4a59STigran Mkrtchyan 750362cd4a59STigran Mkrtchyan void 7504b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 7505b60e9859SChristoph Hellwig union nfsd4_op_u *u) 750662cd4a59STigran Mkrtchyan { 7507b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 750862cd4a59STigran Mkrtchyan } 750962cd4a59STigran Mkrtchyan 751062cd4a59STigran Mkrtchyan /* 751162cd4a59STigran Mkrtchyan * functions to consume current state id 751262cd4a59STigran Mkrtchyan */ 75131e97b519STigran Mkrtchyan 75141e97b519STigran Mkrtchyan void 751557832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 751657832e7bSChristoph Hellwig union nfsd4_op_u *u) 75179428fe1aSTigran Mkrtchyan { 751857832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 75199428fe1aSTigran Mkrtchyan } 75209428fe1aSTigran Mkrtchyan 75219428fe1aSTigran Mkrtchyan void 752257832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 752357832e7bSChristoph Hellwig union nfsd4_op_u *u) 75249428fe1aSTigran Mkrtchyan { 752557832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 75269428fe1aSTigran Mkrtchyan } 75279428fe1aSTigran Mkrtchyan 75289428fe1aSTigran Mkrtchyan void 752957832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 753057832e7bSChristoph Hellwig union nfsd4_op_u *u) 75311e97b519STigran Mkrtchyan { 753257832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 75331e97b519STigran Mkrtchyan } 75341e97b519STigran Mkrtchyan 75351e97b519STigran Mkrtchyan void 753657832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 753757832e7bSChristoph Hellwig union nfsd4_op_u *u) 75381e97b519STigran Mkrtchyan { 753957832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 75401e97b519STigran Mkrtchyan } 75411e97b519STigran Mkrtchyan 754262cd4a59STigran Mkrtchyan void 754357832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 754457832e7bSChristoph Hellwig union nfsd4_op_u *u) 75458b70484cSTigran Mkrtchyan { 754657832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 75478b70484cSTigran Mkrtchyan } 75488b70484cSTigran Mkrtchyan 75498b70484cSTigran Mkrtchyan void 755057832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 755157832e7bSChristoph Hellwig union nfsd4_op_u *u) 75528b70484cSTigran Mkrtchyan { 755357832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 75548b70484cSTigran Mkrtchyan } 755530813e27STigran Mkrtchyan 755630813e27STigran Mkrtchyan void 755757832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 755857832e7bSChristoph Hellwig union nfsd4_op_u *u) 755930813e27STigran Mkrtchyan { 756057832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 756130813e27STigran Mkrtchyan } 756230813e27STigran Mkrtchyan 756330813e27STigran Mkrtchyan void 756457832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 756557832e7bSChristoph Hellwig union nfsd4_op_u *u) 756630813e27STigran Mkrtchyan { 756757832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 756830813e27STigran Mkrtchyan } 7569