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> 46472d155aSNeilBrown #include <linux/fsnotify.h> 47f4e44b39SDai Ngo #include <linux/nfs_ssc.h> 489a74af21SBoaz Harrosh #include "xdr4.h" 4906b332a5SJ. Bruce Fields #include "xdr4cb.h" 500a3adadeSJ. Bruce Fields #include "vfs.h" 51bfa4b365SJ. Bruce Fields #include "current_stateid.h" 521da177e4SLinus Torvalds 535e1533c7SStanislav Kinsbursky #include "netns.h" 549cf514ccSChristoph Hellwig #include "pnfs.h" 55fd4f83fdSJeff Layton #include "filecache.h" 56dd5e3fbcSChuck Lever #include "trace.h" 575e1533c7SStanislav Kinsbursky 581da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 591da177e4SLinus Torvalds 60f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 61f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 62f32f3c2dSJ. Bruce Fields .si_generation = ~0, 63f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 64f32f3c2dSJ. Bruce Fields }; 65f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 66f32f3c2dSJ. Bruce Fields /* all fields zero */ 67f32f3c2dSJ. Bruce Fields }; 6819ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 6919ff0f28STigran Mkrtchyan .si_generation = 1, 7019ff0f28STigran Mkrtchyan }; 71fb500a7cSTrond Myklebust static const stateid_t close_stateid = { 72fb500a7cSTrond Myklebust .si_generation = 0xffffffffU, 73fb500a7cSTrond Myklebust }; 74f32f3c2dSJ. Bruce Fields 75ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 76fd39ca9aSNeilBrown 77f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 78f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 7919ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 80ae254dacSAndrew Elble #define CLOSE_STATEID(stateid) (!memcmp((stateid), &close_stateid, sizeof(stateid_t))) 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* forward declarations */ 83f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 846011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 85362063a5SScott Mayhew void nfsd4_end_grace(struct nfsd_net *nn); 86624322f1SOlga Kornievskaia static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); 871da177e4SLinus Torvalds 888b671b80SJ. Bruce Fields /* Locking: */ 898b671b80SJ. Bruce Fields 908b671b80SJ. Bruce Fields /* 918b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 928b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 938b671b80SJ. Bruce Fields * eventually cover more: 948b671b80SJ. Bruce Fields */ 95cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 968b671b80SJ. Bruce Fields 974f34bd05SAndrew Elble enum nfsd4_st_mutex_lock_subclass { 984f34bd05SAndrew Elble OPEN_STATEID_MUTEX = 0, 994f34bd05SAndrew Elble LOCK_STATEID_MUTEX = 1, 1004f34bd05SAndrew Elble }; 1014f34bd05SAndrew Elble 102b401be22SJeff Layton /* 103b401be22SJeff Layton * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for 104b401be22SJeff Layton * the refcount on the open stateid to drop. 105b401be22SJeff Layton */ 106b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq); 107b401be22SJeff Layton 10889c905beSJ. Bruce Fields /* 10989c905beSJ. Bruce Fields * A waitqueue where a writer to clients/#/ctl destroying a client can 11089c905beSJ. Bruce Fields * wait for cl_rpc_users to drop to 0 and then for the client to be 11189c905beSJ. Bruce Fields * unhashed. 11289c905beSJ. Bruce Fields */ 11389c905beSJ. Bruce Fields static DECLARE_WAIT_QUEUE_HEAD(expiry_wq); 11489c905beSJ. Bruce Fields 1159258a2d5SJeff Layton static struct kmem_cache *client_slab; 116abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 117abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 118abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 119abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 120abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 1218287f009SSachin Bhamare static struct kmem_cache *odstate_slab; 122e60d4398SNeilBrown 12366b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 124508dc6e1SBenny Halevy 125c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; 12676d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; 1270162ac2bSChristoph Hellwig 12866af2579SDai Ngo static struct workqueue_struct *laundry_wq; 12966af2579SDai Ngo 13066b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 131508dc6e1SBenny Halevy { 13266b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 13366b2b9b2SJ. Bruce Fields } 13466b2b9b2SJ. Bruce Fields 135f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 136f0f51f5cSJ. Bruce Fields { 137f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 13866b2b9b2SJ. Bruce Fields return nfserr_jukebox; 13966b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 14066b2b9b2SJ. Bruce Fields return nfs_ok; 14166b2b9b2SJ. Bruce Fields } 14266b2b9b2SJ. Bruce Fields 143221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 144221a6876SJ. Bruce Fields { 145221a6876SJ. Bruce Fields return clp->cl_time == 0; 146221a6876SJ. Bruce Fields } 147221a6876SJ. Bruce Fields 148221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 149221a6876SJ. Bruce Fields { 1500a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1510a880a28STrond Myklebust 1520a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1530a880a28STrond Myklebust 154221a6876SJ. Bruce Fields if (is_client_expired(clp)) 155221a6876SJ. Bruce Fields return nfserr_expired; 15614ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 15766af2579SDai Ngo clp->cl_state = NFSD4_ACTIVE; 158221a6876SJ. Bruce Fields return nfs_ok; 159221a6876SJ. Bruce Fields } 160221a6876SJ. Bruce Fields 161221a6876SJ. Bruce Fields /* must be called under the client_lock */ 162221a6876SJ. Bruce Fields static inline void 163221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 164221a6876SJ. Bruce Fields { 165221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 166221a6876SJ. Bruce Fields 167221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 168221a6876SJ. Bruce Fields WARN_ON(1); 169221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 170221a6876SJ. Bruce Fields __func__, 171221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 172221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 173221a6876SJ. Bruce Fields return; 174221a6876SJ. Bruce Fields } 175221a6876SJ. Bruce Fields 176221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 17720b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 17866af2579SDai Ngo clp->cl_state = NFSD4_ACTIVE; 179221a6876SJ. Bruce Fields } 180221a6876SJ. Bruce Fields 181ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 182221a6876SJ. Bruce Fields { 1830a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1840a880a28STrond Myklebust 1850a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1860a880a28STrond Myklebust 18714ed14ccSJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_rpc_users)) 188221a6876SJ. Bruce Fields return; 189221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 190221a6876SJ. Bruce Fields renew_client_locked(clp); 19189c905beSJ. Bruce Fields else 19289c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 193221a6876SJ. Bruce Fields } 194221a6876SJ. Bruce Fields 1954b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 1964b24ca7dSJeff Layton { 1974b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1984b24ca7dSJeff Layton 19914ed14ccSJ. Bruce Fields if (!atomic_dec_and_lock(&clp->cl_rpc_users, &nn->client_lock)) 200d6c249b4SJeff Layton return; 201d6c249b4SJeff Layton if (!is_client_expired(clp)) 202d6c249b4SJeff Layton renew_client_locked(clp); 20389c905beSJ. Bruce Fields else 20489c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 2054b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 2064b24ca7dSJeff Layton } 2074b24ca7dSJeff Layton 208d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 209d4e19e70STrond Myklebust { 210d4e19e70STrond Myklebust __be32 status; 211d4e19e70STrond Myklebust 212d4e19e70STrond Myklebust if (is_session_dead(ses)) 213d4e19e70STrond Myklebust return nfserr_badsession; 214d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 215d4e19e70STrond Myklebust if (status) 216d4e19e70STrond Myklebust return status; 217d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 218d4e19e70STrond Myklebust return nfs_ok; 219d4e19e70STrond Myklebust } 220d4e19e70STrond Myklebust 221d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 222d4e19e70STrond Myklebust { 223d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 2240a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2250a880a28STrond Myklebust 2260a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 227d4e19e70STrond Myklebust 228d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 229d4e19e70STrond Myklebust free_session(ses); 230d4e19e70STrond Myklebust put_client_renew_locked(clp); 231d4e19e70STrond Myklebust } 232d4e19e70STrond Myklebust 233d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 234d4e19e70STrond Myklebust { 235d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 236d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 237d4e19e70STrond Myklebust 238d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 239d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 240d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 241d4e19e70STrond Myklebust } 242d4e19e70STrond Myklebust 24376d348faSJeff Layton static struct nfsd4_blocked_lock * 24476d348faSJeff Layton find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 24576d348faSJeff Layton struct nfsd_net *nn) 24676d348faSJeff Layton { 24776d348faSJeff Layton struct nfsd4_blocked_lock *cur, *found = NULL; 24876d348faSJeff Layton 2490cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 25076d348faSJeff Layton list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { 25176d348faSJeff Layton if (fh_match(fh, &cur->nbl_fh)) { 25276d348faSJeff Layton list_del_init(&cur->nbl_list); 25347446d74SVasily Averin WARN_ON(list_empty(&cur->nbl_lru)); 2547919d0a2SJeff Layton list_del_init(&cur->nbl_lru); 25576d348faSJeff Layton found = cur; 25676d348faSJeff Layton break; 25776d348faSJeff Layton } 25876d348faSJeff Layton } 2590cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 26076d348faSJeff Layton if (found) 261cb03f94fSNeilBrown locks_delete_block(&found->nbl_lock); 26276d348faSJeff Layton return found; 26376d348faSJeff Layton } 26476d348faSJeff Layton 26576d348faSJeff Layton static struct nfsd4_blocked_lock * 26676d348faSJeff Layton find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 26776d348faSJeff Layton struct nfsd_net *nn) 26876d348faSJeff Layton { 26976d348faSJeff Layton struct nfsd4_blocked_lock *nbl; 27076d348faSJeff Layton 27176d348faSJeff Layton nbl = find_blocked_lock(lo, fh, nn); 27276d348faSJeff Layton if (!nbl) { 27376d348faSJeff Layton nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); 27476d348faSJeff Layton if (nbl) { 275e1e8399eSVasily Averin INIT_LIST_HEAD(&nbl->nbl_list); 276e1e8399eSVasily Averin INIT_LIST_HEAD(&nbl->nbl_lru); 27776d348faSJeff Layton fh_copy_shallow(&nbl->nbl_fh, fh); 27876d348faSJeff Layton locks_init_lock(&nbl->nbl_lock); 27947446d74SVasily Averin kref_init(&nbl->nbl_kref); 28076d348faSJeff Layton nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client, 28176d348faSJeff Layton &nfsd4_cb_notify_lock_ops, 28276d348faSJeff Layton NFSPROC4_CLNT_CB_NOTIFY_LOCK); 28376d348faSJeff Layton } 28476d348faSJeff Layton } 28576d348faSJeff Layton return nbl; 28676d348faSJeff Layton } 28776d348faSJeff Layton 28876d348faSJeff Layton static void 28947446d74SVasily Averin free_nbl(struct kref *kref) 29047446d74SVasily Averin { 29147446d74SVasily Averin struct nfsd4_blocked_lock *nbl; 29247446d74SVasily Averin 29347446d74SVasily Averin nbl = container_of(kref, struct nfsd4_blocked_lock, nbl_kref); 29447446d74SVasily Averin kfree(nbl); 29547446d74SVasily Averin } 29647446d74SVasily Averin 29747446d74SVasily Averin static void 29876d348faSJeff Layton free_blocked_lock(struct nfsd4_blocked_lock *nbl) 29976d348faSJeff Layton { 3006aaafc43SJeff Layton locks_delete_block(&nbl->nbl_lock); 30176d348faSJeff Layton locks_release_private(&nbl->nbl_lock); 30247446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 30376d348faSJeff Layton } 30476d348faSJeff Layton 30568ef3bc3SJeff Layton static void 30668ef3bc3SJeff Layton remove_blocked_locks(struct nfs4_lockowner *lo) 30768ef3bc3SJeff Layton { 30868ef3bc3SJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 30968ef3bc3SJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 31068ef3bc3SJeff Layton struct nfsd4_blocked_lock *nbl; 31168ef3bc3SJeff Layton LIST_HEAD(reaplist); 31268ef3bc3SJeff Layton 31368ef3bc3SJeff Layton /* Dequeue all blocked locks */ 31468ef3bc3SJeff Layton spin_lock(&nn->blocked_locks_lock); 31568ef3bc3SJeff Layton while (!list_empty(&lo->lo_blocked)) { 31668ef3bc3SJeff Layton nbl = list_first_entry(&lo->lo_blocked, 31768ef3bc3SJeff Layton struct nfsd4_blocked_lock, 31868ef3bc3SJeff Layton nbl_list); 31968ef3bc3SJeff Layton list_del_init(&nbl->nbl_list); 32047446d74SVasily Averin WARN_ON(list_empty(&nbl->nbl_lru)); 32168ef3bc3SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 32268ef3bc3SJeff Layton } 32368ef3bc3SJeff Layton spin_unlock(&nn->blocked_locks_lock); 32468ef3bc3SJeff Layton 32568ef3bc3SJeff Layton /* Now free them */ 32668ef3bc3SJeff Layton while (!list_empty(&reaplist)) { 32768ef3bc3SJeff Layton nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, 32868ef3bc3SJeff Layton nbl_lru); 32968ef3bc3SJeff Layton list_del_init(&nbl->nbl_lru); 33068ef3bc3SJeff Layton free_blocked_lock(nbl); 33168ef3bc3SJeff Layton } 33268ef3bc3SJeff Layton } 33368ef3bc3SJeff Layton 334f456458eSJeff Layton static void 335f456458eSJeff Layton nfsd4_cb_notify_lock_prepare(struct nfsd4_callback *cb) 336f456458eSJeff Layton { 337f456458eSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(cb, 338f456458eSJeff Layton struct nfsd4_blocked_lock, nbl_cb); 339f456458eSJeff Layton locks_delete_block(&nbl->nbl_lock); 340f456458eSJeff Layton } 341f456458eSJeff Layton 34276d348faSJeff Layton static int 34376d348faSJeff Layton nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) 34476d348faSJeff Layton { 34576d348faSJeff Layton /* 34676d348faSJeff Layton * Since this is just an optimization, we don't try very hard if it 34776d348faSJeff Layton * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and 34876d348faSJeff Layton * just quit trying on anything else. 34976d348faSJeff Layton */ 35076d348faSJeff Layton switch (task->tk_status) { 35176d348faSJeff Layton case -NFS4ERR_DELAY: 35276d348faSJeff Layton rpc_delay(task, 1 * HZ); 35376d348faSJeff Layton return 0; 35476d348faSJeff Layton default: 35576d348faSJeff Layton return 1; 35676d348faSJeff Layton } 35776d348faSJeff Layton } 35876d348faSJeff Layton 35976d348faSJeff Layton static void 36076d348faSJeff Layton nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb) 36176d348faSJeff Layton { 36276d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(cb, 36376d348faSJeff Layton struct nfsd4_blocked_lock, nbl_cb); 36476d348faSJeff Layton 36576d348faSJeff Layton free_blocked_lock(nbl); 36676d348faSJeff Layton } 36776d348faSJeff Layton 36876d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { 369f456458eSJeff Layton .prepare = nfsd4_cb_notify_lock_prepare, 37076d348faSJeff Layton .done = nfsd4_cb_notify_lock_done, 37176d348faSJeff Layton .release = nfsd4_cb_notify_lock_release, 37276d348faSJeff Layton }; 37376d348faSJeff Layton 374ebd9d2c2SJ. Bruce Fields /* 375ebd9d2c2SJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 376ebd9d2c2SJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 377ebd9d2c2SJ. Bruce Fields * only what share bits are currently in force, but also what 378ebd9d2c2SJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 3793dcd1d8aSJ. Bruce Fields * to enforce the recommendation in 3803dcd1d8aSJ. Bruce Fields * https://datatracker.ietf.org/doc/html/rfc7530#section-16.19.4 that 3813dcd1d8aSJ. Bruce Fields * the server return an error if the client attempt to downgrade to a 3823dcd1d8aSJ. Bruce Fields * combination of share bits not explicable by closing some of its 3833dcd1d8aSJ. Bruce Fields * previous opens. 384ebd9d2c2SJ. Bruce Fields * 3853dcd1d8aSJ. Bruce Fields * This enforcement is arguably incomplete, since we don't keep 386ebd9d2c2SJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 387ebd9d2c2SJ. Bruce Fields * 388ebd9d2c2SJ. Bruce Fields * OPEN allow read, deny write 389ebd9d2c2SJ. Bruce Fields * OPEN allow both, deny none 390ebd9d2c2SJ. Bruce Fields * DOWNGRADE allow read, deny none 391ebd9d2c2SJ. Bruce Fields * 392ebd9d2c2SJ. Bruce Fields * which we should reject. 3933dcd1d8aSJ. Bruce Fields * 3943dcd1d8aSJ. Bruce Fields * But you could also argue that our current code is already overkill, 3953dcd1d8aSJ. Bruce Fields * since it only exists to return NFS4ERR_INVAL on incorrect client 3963dcd1d8aSJ. Bruce Fields * behavior. 397ebd9d2c2SJ. Bruce Fields */ 398ebd9d2c2SJ. Bruce Fields static unsigned int 399ebd9d2c2SJ. Bruce Fields bmap_to_share_mode(unsigned long bmap) 400ebd9d2c2SJ. Bruce Fields { 401ebd9d2c2SJ. Bruce Fields int i; 402ebd9d2c2SJ. Bruce Fields unsigned int access = 0; 403ebd9d2c2SJ. Bruce Fields 404ebd9d2c2SJ. Bruce Fields for (i = 1; i < 4; i++) { 405ebd9d2c2SJ. Bruce Fields if (test_bit(i, &bmap)) 406ebd9d2c2SJ. Bruce Fields access |= i; 407ebd9d2c2SJ. Bruce Fields } 408ebd9d2c2SJ. Bruce Fields return access; 409ebd9d2c2SJ. Bruce Fields } 410ebd9d2c2SJ. Bruce Fields 411ebd9d2c2SJ. Bruce Fields /* set share access for a given stateid */ 412ebd9d2c2SJ. Bruce Fields static inline void 413ebd9d2c2SJ. Bruce Fields set_access(u32 access, struct nfs4_ol_stateid *stp) 414ebd9d2c2SJ. Bruce Fields { 415ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << access; 416ebd9d2c2SJ. Bruce Fields 417ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 418ebd9d2c2SJ. Bruce Fields stp->st_access_bmap |= mask; 419ebd9d2c2SJ. Bruce Fields } 420ebd9d2c2SJ. Bruce Fields 421ebd9d2c2SJ. Bruce Fields /* clear share access for a given stateid */ 422ebd9d2c2SJ. Bruce Fields static inline void 423ebd9d2c2SJ. Bruce Fields clear_access(u32 access, struct nfs4_ol_stateid *stp) 424ebd9d2c2SJ. Bruce Fields { 425ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << access; 426ebd9d2c2SJ. Bruce Fields 427ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 428ebd9d2c2SJ. Bruce Fields stp->st_access_bmap &= ~mask; 429ebd9d2c2SJ. Bruce Fields } 430ebd9d2c2SJ. Bruce Fields 431ebd9d2c2SJ. Bruce Fields /* test whether a given stateid has access */ 432ebd9d2c2SJ. Bruce Fields static inline bool 433ebd9d2c2SJ. Bruce Fields test_access(u32 access, struct nfs4_ol_stateid *stp) 434ebd9d2c2SJ. Bruce Fields { 435ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << access; 436ebd9d2c2SJ. Bruce Fields 437ebd9d2c2SJ. Bruce Fields return (bool)(stp->st_access_bmap & mask); 438ebd9d2c2SJ. Bruce Fields } 439ebd9d2c2SJ. Bruce Fields 440ebd9d2c2SJ. Bruce Fields /* set share deny for a given stateid */ 441ebd9d2c2SJ. Bruce Fields static inline void 442ebd9d2c2SJ. Bruce Fields set_deny(u32 deny, struct nfs4_ol_stateid *stp) 443ebd9d2c2SJ. Bruce Fields { 444ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << deny; 445ebd9d2c2SJ. Bruce Fields 446ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 447ebd9d2c2SJ. Bruce Fields stp->st_deny_bmap |= mask; 448ebd9d2c2SJ. Bruce Fields } 449ebd9d2c2SJ. Bruce Fields 450ebd9d2c2SJ. Bruce Fields /* clear share deny for a given stateid */ 451ebd9d2c2SJ. Bruce Fields static inline void 452ebd9d2c2SJ. Bruce Fields clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 453ebd9d2c2SJ. Bruce Fields { 454ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << deny; 455ebd9d2c2SJ. Bruce Fields 456ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 457ebd9d2c2SJ. Bruce Fields stp->st_deny_bmap &= ~mask; 458ebd9d2c2SJ. Bruce Fields } 459ebd9d2c2SJ. Bruce Fields 460ebd9d2c2SJ. Bruce Fields /* test whether a given stateid is denying specific access */ 461ebd9d2c2SJ. Bruce Fields static inline bool 462ebd9d2c2SJ. Bruce Fields test_deny(u32 deny, struct nfs4_ol_stateid *stp) 463ebd9d2c2SJ. Bruce Fields { 464ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << deny; 465ebd9d2c2SJ. Bruce Fields 466ebd9d2c2SJ. Bruce Fields return (bool)(stp->st_deny_bmap & mask); 467ebd9d2c2SJ. Bruce Fields } 468ebd9d2c2SJ. Bruce Fields 469ebd9d2c2SJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 470ebd9d2c2SJ. Bruce Fields { 471ebd9d2c2SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 472ebd9d2c2SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 473ebd9d2c2SJ. Bruce Fields return O_RDONLY; 474ebd9d2c2SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 475ebd9d2c2SJ. Bruce Fields return O_WRONLY; 476ebd9d2c2SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 477ebd9d2c2SJ. Bruce Fields return O_RDWR; 478ebd9d2c2SJ. Bruce Fields } 479ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(1); 480ebd9d2c2SJ. Bruce Fields return O_RDONLY; 481ebd9d2c2SJ. Bruce Fields } 482ebd9d2c2SJ. Bruce Fields 483ebd9d2c2SJ. Bruce Fields static inline int 484ebd9d2c2SJ. Bruce Fields access_permit_read(struct nfs4_ol_stateid *stp) 485ebd9d2c2SJ. Bruce Fields { 486ebd9d2c2SJ. Bruce Fields return test_access(NFS4_SHARE_ACCESS_READ, stp) || 487ebd9d2c2SJ. Bruce Fields test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 488ebd9d2c2SJ. Bruce Fields test_access(NFS4_SHARE_ACCESS_WRITE, stp); 489ebd9d2c2SJ. Bruce Fields } 490ebd9d2c2SJ. Bruce Fields 491ebd9d2c2SJ. Bruce Fields static inline int 492ebd9d2c2SJ. Bruce Fields access_permit_write(struct nfs4_ol_stateid *stp) 493ebd9d2c2SJ. Bruce Fields { 494ebd9d2c2SJ. Bruce Fields return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 495ebd9d2c2SJ. Bruce Fields test_access(NFS4_SHARE_ACCESS_BOTH, stp); 496ebd9d2c2SJ. Bruce Fields } 497ebd9d2c2SJ. Bruce Fields 498b5971afaSKinglong Mee static inline struct nfs4_stateowner * 499b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop) 500b5971afaSKinglong Mee { 501b5971afaSKinglong Mee atomic_inc(&sop->so_count); 502b5971afaSKinglong Mee return sop; 503b5971afaSKinglong Mee } 504b5971afaSKinglong Mee 5057ffb5880STrond Myklebust static int 506d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) 5077ffb5880STrond Myklebust { 5087ffb5880STrond Myklebust return (sop->so_owner.len == owner->len) && 509d4f0489fSTrond Myklebust 0 == memcmp(sop->so_owner.data, owner->data, owner->len); 5107ffb5880STrond Myklebust } 5117ffb5880STrond Myklebust 5127ffb5880STrond Myklebust static struct nfs4_openowner * 5137ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, 514d4f0489fSTrond Myklebust struct nfs4_client *clp) 5157ffb5880STrond Myklebust { 5167ffb5880STrond Myklebust struct nfs4_stateowner *so; 5177ffb5880STrond Myklebust 518d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 5197ffb5880STrond Myklebust 520d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval], 521d4f0489fSTrond Myklebust so_strhash) { 5227ffb5880STrond Myklebust if (!so->so_is_open_owner) 5237ffb5880STrond Myklebust continue; 524b5971afaSKinglong Mee if (same_owner_str(so, &open->op_owner)) 525b5971afaSKinglong Mee return openowner(nfs4_get_stateowner(so)); 5267ffb5880STrond Myklebust } 5277ffb5880STrond Myklebust return NULL; 5287ffb5880STrond Myklebust } 5297ffb5880STrond Myklebust 5307ffb5880STrond Myklebust static struct nfs4_openowner * 5317ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 532d4f0489fSTrond Myklebust struct nfs4_client *clp) 5337ffb5880STrond Myklebust { 5347ffb5880STrond Myklebust struct nfs4_openowner *oo; 5357ffb5880STrond Myklebust 536d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 537d4f0489fSTrond Myklebust oo = find_openstateowner_str_locked(hashval, open, clp); 538d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5397ffb5880STrond Myklebust return oo; 5407ffb5880STrond Myklebust } 5417ffb5880STrond Myklebust 5421da177e4SLinus Torvalds static inline u32 5431da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 5441da177e4SLinus Torvalds { 5451da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds u32 x = 0; 5481da177e4SLinus Torvalds while (nbytes--) { 5491da177e4SLinus Torvalds x *= 37; 5501da177e4SLinus Torvalds x += *cptr++; 5511da177e4SLinus Torvalds } 5521da177e4SLinus Torvalds return x; 5531da177e4SLinus Torvalds } 5541da177e4SLinus Torvalds 5555b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu) 55632513b40SJ. Bruce Fields { 5575b095e99SJeff Layton struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu); 5585b095e99SJeff Layton 5595b095e99SJeff Layton kmem_cache_free(file_slab, fp); 56032513b40SJ. Bruce Fields } 56132513b40SJ. Bruce Fields 562e6ba76e1SChristoph Hellwig void 56313cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 56413cd2184SNeilBrown { 56502e1215fSJeff Layton might_lock(&state_lock); 56602e1215fSJeff Layton 567818a34ebSElena Reshetova if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) { 5685b095e99SJeff Layton hlist_del_rcu(&fi->fi_hash); 569cdc97505SBenny Halevy spin_unlock(&state_lock); 5708287f009SSachin Bhamare WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); 5715b095e99SJeff Layton WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); 5725b095e99SJeff Layton call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); 5738b671b80SJ. Bruce Fields } 57413cd2184SNeilBrown } 57513cd2184SNeilBrown 576eb82dd39SJeff Layton static struct nfsd_file * 577de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag) 578de18643dSTrond Myklebust { 579de18643dSTrond Myklebust if (f->fi_fds[oflag]) 580eb82dd39SJeff Layton return nfsd_file_get(f->fi_fds[oflag]); 581de18643dSTrond Myklebust return NULL; 582de18643dSTrond Myklebust } 583de18643dSTrond Myklebust 584eb82dd39SJeff Layton static struct nfsd_file * 585de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f) 586de18643dSTrond Myklebust { 587eb82dd39SJeff Layton struct nfsd_file *ret; 588de18643dSTrond Myklebust 589de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 590de18643dSTrond Myklebust 591de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 592de18643dSTrond Myklebust if (!ret) 593de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 594de18643dSTrond Myklebust return ret; 595de18643dSTrond Myklebust } 596de18643dSTrond Myklebust 597eb82dd39SJeff Layton static struct nfsd_file * 598de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 599de18643dSTrond Myklebust { 600eb82dd39SJeff Layton struct nfsd_file *ret; 601de18643dSTrond Myklebust 602de18643dSTrond Myklebust spin_lock(&f->fi_lock); 603de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 604de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 605de18643dSTrond Myklebust 606de18643dSTrond Myklebust return ret; 607de18643dSTrond Myklebust } 608de18643dSTrond Myklebust 609eb82dd39SJeff Layton static struct nfsd_file * 610eb82dd39SJeff Layton find_readable_file_locked(struct nfs4_file *f) 611de18643dSTrond Myklebust { 612eb82dd39SJeff Layton struct nfsd_file *ret; 613de18643dSTrond Myklebust 614de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 615de18643dSTrond Myklebust 616de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 617de18643dSTrond Myklebust if (!ret) 618de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 619de18643dSTrond Myklebust return ret; 620de18643dSTrond Myklebust } 621de18643dSTrond Myklebust 622eb82dd39SJeff Layton static struct nfsd_file * 623de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 624de18643dSTrond Myklebust { 625eb82dd39SJeff Layton struct nfsd_file *ret; 626de18643dSTrond Myklebust 627de18643dSTrond Myklebust spin_lock(&f->fi_lock); 628de18643dSTrond Myklebust ret = find_readable_file_locked(f); 629de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 630de18643dSTrond Myklebust 631de18643dSTrond Myklebust return ret; 632de18643dSTrond Myklebust } 633de18643dSTrond Myklebust 634eb82dd39SJeff Layton struct nfsd_file * 635de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 636de18643dSTrond Myklebust { 637eb82dd39SJeff Layton struct nfsd_file *ret; 638de18643dSTrond Myklebust 639a451b123STrond Myklebust if (!f) 640a451b123STrond Myklebust return NULL; 641de18643dSTrond Myklebust spin_lock(&f->fi_lock); 642de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 643de18643dSTrond Myklebust if (!ret) { 644de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 645de18643dSTrond Myklebust if (!ret) 646de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 647de18643dSTrond Myklebust } 648de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 649de18643dSTrond Myklebust return ret; 650de18643dSTrond Myklebust } 651de18643dSTrond Myklebust 6529affa435SJ. Bruce Fields static struct nfsd_file *find_deleg_file(struct nfs4_file *f) 6539affa435SJ. Bruce Fields { 6549affa435SJ. Bruce Fields struct nfsd_file *ret = NULL; 6559affa435SJ. Bruce Fields 6569affa435SJ. Bruce Fields spin_lock(&f->fi_lock); 6579affa435SJ. Bruce Fields if (f->fi_deleg_file) 6589affa435SJ. Bruce Fields ret = nfsd_file_get(f->fi_deleg_file); 6599affa435SJ. Bruce Fields spin_unlock(&f->fi_lock); 6609affa435SJ. Bruce Fields return ret; 6619affa435SJ. Bruce Fields } 6629affa435SJ. Bruce Fields 66302a3508dSTrond Myklebust static atomic_long_t num_delegations; 664697ce9beSZhang Yanfei unsigned long max_delegations; 665ef0f3390SNeilBrown 666ef0f3390SNeilBrown /* 667ef0f3390SNeilBrown * Open owner state (share locks) 668ef0f3390SNeilBrown */ 669ef0f3390SNeilBrown 67016bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 67116bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 67216bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 67316bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 674ef0f3390SNeilBrown 675d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 676ddc04c41SJ. Bruce Fields { 677ddc04c41SJ. Bruce Fields unsigned int ret; 678ddc04c41SJ. Bruce Fields 679ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 68016bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 681ddc04c41SJ. Bruce Fields } 682ef0f3390SNeilBrown 683ef0f3390SNeilBrown /* hash table for nfs4_file */ 684ef0f3390SNeilBrown #define FILE_HASH_BITS 8 685ef0f3390SNeilBrown #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) 68635079582SShan Wei 687f9b60e22SJ. Bruce Fields static unsigned int file_hashval(struct svc_fh *fh) 688ddc04c41SJ. Bruce Fields { 689f9b60e22SJ. Bruce Fields struct inode *inode = d_inode(fh->fh_dentry); 690ca943217STrond Myklebust 691f9b60e22SJ. Bruce Fields /* XXX: why not (here & in file cache) use inode? */ 692f9b60e22SJ. Bruce Fields return (unsigned int)hash_long(inode->i_ino, FILE_HASH_BITS); 693ca943217STrond Myklebust } 694ca943217STrond Myklebust 69589876f8cSJeff Layton static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; 696ef0f3390SNeilBrown 697*3d694271SDai Ngo /* 698*3d694271SDai Ngo * Check if courtesy clients have conflicting access and resolve it if possible 699*3d694271SDai Ngo * 700*3d694271SDai Ngo * access: is op_share_access if share_access is true. 701*3d694271SDai Ngo * Check if access mode, op_share_access, would conflict with 702*3d694271SDai Ngo * the current deny mode of the file 'fp'. 703*3d694271SDai Ngo * access: is op_share_deny if share_access is false. 704*3d694271SDai Ngo * Check if the deny mode, op_share_deny, would conflict with 705*3d694271SDai Ngo * current access of the file 'fp'. 706*3d694271SDai Ngo * stp: skip checking this entry. 707*3d694271SDai Ngo * new_stp: normal open, not open upgrade. 708*3d694271SDai Ngo * 709*3d694271SDai Ngo * Function returns: 710*3d694271SDai Ngo * false - access/deny mode conflict with normal client. 711*3d694271SDai Ngo * true - no conflict or conflict with courtesy client(s) is resolved. 712*3d694271SDai Ngo */ 713*3d694271SDai Ngo static bool 714*3d694271SDai Ngo nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp, 715*3d694271SDai Ngo struct nfs4_ol_stateid *stp, u32 access, bool share_access) 716*3d694271SDai Ngo { 717*3d694271SDai Ngo struct nfs4_ol_stateid *st; 718*3d694271SDai Ngo bool resolvable = true; 719*3d694271SDai Ngo unsigned char bmap; 720*3d694271SDai Ngo struct nfsd_net *nn; 721*3d694271SDai Ngo struct nfs4_client *clp; 722*3d694271SDai Ngo 723*3d694271SDai Ngo lockdep_assert_held(&fp->fi_lock); 724*3d694271SDai Ngo list_for_each_entry(st, &fp->fi_stateids, st_perfile) { 725*3d694271SDai Ngo /* ignore lock stateid */ 726*3d694271SDai Ngo if (st->st_openstp) 727*3d694271SDai Ngo continue; 728*3d694271SDai Ngo if (st == stp && new_stp) 729*3d694271SDai Ngo continue; 730*3d694271SDai Ngo /* check file access against deny mode or vice versa */ 731*3d694271SDai Ngo bmap = share_access ? st->st_deny_bmap : st->st_access_bmap; 732*3d694271SDai Ngo if (!(access & bmap_to_share_mode(bmap))) 733*3d694271SDai Ngo continue; 734*3d694271SDai Ngo clp = st->st_stid.sc_client; 735*3d694271SDai Ngo if (try_to_expire_client(clp)) 736*3d694271SDai Ngo continue; 737*3d694271SDai Ngo resolvable = false; 738*3d694271SDai Ngo break; 739*3d694271SDai Ngo } 740*3d694271SDai Ngo if (resolvable) { 741*3d694271SDai Ngo clp = stp->st_stid.sc_client; 742*3d694271SDai Ngo nn = net_generic(clp->net, nfsd_net_id); 743*3d694271SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 744*3d694271SDai Ngo } 745*3d694271SDai Ngo return resolvable; 746*3d694271SDai Ngo } 747*3d694271SDai Ngo 74812659651SJeff Layton static void 74912659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 7503477565eSJ. Bruce Fields { 7517214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 7527214e860SJeff Layton 75312659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 75412659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 75512659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 75612659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 7573477565eSJ. Bruce Fields } 7583477565eSJ. Bruce Fields 75912659651SJeff Layton static __be32 76012659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 761998db52cSJ. Bruce Fields { 7627214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 7637214e860SJeff Layton 76412659651SJeff Layton /* Does this access mode make sense? */ 76512659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 76612659651SJeff Layton return nfserr_inval; 76712659651SJeff Layton 768baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 769baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 770baeb4ff0SJeff Layton return nfserr_share_denied; 771baeb4ff0SJeff Layton 77212659651SJeff Layton __nfs4_file_get_access(fp, access); 77312659651SJeff Layton return nfs_ok; 774998db52cSJ. Bruce Fields } 775998db52cSJ. Bruce Fields 776baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 777baeb4ff0SJeff Layton { 778baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 779baeb4ff0SJeff Layton if (deny) { 780baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 781baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 782baeb4ff0SJeff Layton return nfserr_inval; 783baeb4ff0SJeff Layton 784baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 785baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 786baeb4ff0SJeff Layton return nfserr_share_denied; 787baeb4ff0SJeff Layton 788baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 789baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 790baeb4ff0SJeff Layton return nfserr_share_denied; 791baeb4ff0SJeff Layton } 792baeb4ff0SJeff Layton return nfs_ok; 793baeb4ff0SJeff Layton } 794baeb4ff0SJeff Layton 795998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 796f9d7562fSJ. Bruce Fields { 797de18643dSTrond Myklebust might_lock(&fp->fi_lock); 798de18643dSTrond Myklebust 799de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 800fd4f83fdSJeff Layton struct nfsd_file *f1 = NULL; 801fd4f83fdSJeff Layton struct nfsd_file *f2 = NULL; 802de18643dSTrond Myklebust 8036d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 8040c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 8056d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 806de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 807de18643dSTrond Myklebust if (f1) 808fd4f83fdSJeff Layton nfsd_file_put(f1); 809de18643dSTrond Myklebust if (f2) 810fd4f83fdSJeff Layton nfsd_file_put(f2); 811f9d7562fSJ. Bruce Fields } 812f9d7562fSJ. Bruce Fields } 813f9d7562fSJ. Bruce Fields 81412659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 815998db52cSJ. Bruce Fields { 81612659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 81712659651SJeff Layton 81812659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 819998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 82012659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 82112659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 822998db52cSJ. Bruce Fields } 823998db52cSJ. Bruce Fields 8248287f009SSachin Bhamare /* 8258287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 8268287f009SSachin Bhamare * pNFS for proper return on close semantics. 8278287f009SSachin Bhamare * 8288287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 8298287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 8308287f009SSachin Bhamare */ 8318287f009SSachin Bhamare static struct nfs4_clnt_odstate * 8328287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 8338287f009SSachin Bhamare { 8348287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 8358287f009SSachin Bhamare 8368287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 8378287f009SSachin Bhamare if (co) { 8388287f009SSachin Bhamare co->co_client = clp; 839cff7cb2eSElena Reshetova refcount_set(&co->co_odcount, 1); 8408287f009SSachin Bhamare } 8418287f009SSachin Bhamare return co; 8428287f009SSachin Bhamare } 8438287f009SSachin Bhamare 8448287f009SSachin Bhamare static void 8458287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 8468287f009SSachin Bhamare { 8478287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 8488287f009SSachin Bhamare 8498287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 8508287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 8518287f009SSachin Bhamare } 8528287f009SSachin Bhamare 8538287f009SSachin Bhamare static inline void 8548287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 8558287f009SSachin Bhamare { 8568287f009SSachin Bhamare if (co) 857cff7cb2eSElena Reshetova refcount_inc(&co->co_odcount); 8588287f009SSachin Bhamare } 8598287f009SSachin Bhamare 8608287f009SSachin Bhamare static void 8618287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 8628287f009SSachin Bhamare { 8638287f009SSachin Bhamare struct nfs4_file *fp; 8648287f009SSachin Bhamare 8658287f009SSachin Bhamare if (!co) 8668287f009SSachin Bhamare return; 8678287f009SSachin Bhamare 8688287f009SSachin Bhamare fp = co->co_file; 869cff7cb2eSElena Reshetova if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 8708287f009SSachin Bhamare list_del(&co->co_perfile); 8718287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 8728287f009SSachin Bhamare 8738287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 8748287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 8758287f009SSachin Bhamare } 8768287f009SSachin Bhamare } 8778287f009SSachin Bhamare 8788287f009SSachin Bhamare static struct nfs4_clnt_odstate * 8798287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 8808287f009SSachin Bhamare { 8818287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 8828287f009SSachin Bhamare struct nfs4_client *cl; 8838287f009SSachin Bhamare 8848287f009SSachin Bhamare if (!new) 8858287f009SSachin Bhamare return NULL; 8868287f009SSachin Bhamare 8878287f009SSachin Bhamare cl = new->co_client; 8888287f009SSachin Bhamare 8898287f009SSachin Bhamare spin_lock(&fp->fi_lock); 8908287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 8918287f009SSachin Bhamare if (co->co_client == cl) { 8928287f009SSachin Bhamare get_clnt_odstate(co); 8938287f009SSachin Bhamare goto out; 8948287f009SSachin Bhamare } 8958287f009SSachin Bhamare } 8968287f009SSachin Bhamare co = new; 8978287f009SSachin Bhamare co->co_file = fp; 8988287f009SSachin Bhamare hash_clnt_odstate_locked(new); 8998287f009SSachin Bhamare out: 9008287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 9018287f009SSachin Bhamare return co; 9028287f009SSachin Bhamare } 9038287f009SSachin Bhamare 904d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 905d19fb70dSKinglong Mee void (*sc_free)(struct nfs4_stid *)) 906996e0938SJ. Bruce Fields { 9073abdb607SJ. Bruce Fields struct nfs4_stid *stid; 9083abdb607SJ. Bruce Fields int new_id; 9093abdb607SJ. Bruce Fields 910f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 9113abdb607SJ. Bruce Fields if (!stid) 9123abdb607SJ. Bruce Fields return NULL; 913996e0938SJ. Bruce Fields 9144770d722SJeff Layton idr_preload(GFP_KERNEL); 9154770d722SJeff Layton spin_lock(&cl->cl_lock); 91678599c42SJ. Bruce Fields /* Reserving 0 for start of file in nfsdfs "states" file: */ 91778599c42SJ. Bruce Fields new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 1, 0, GFP_NOWAIT); 9184770d722SJeff Layton spin_unlock(&cl->cl_lock); 9194770d722SJeff Layton idr_preload_end(); 920ebd6c707STejun Heo if (new_id < 0) 9213abdb607SJ. Bruce Fields goto out_free; 922d19fb70dSKinglong Mee 923d19fb70dSKinglong Mee stid->sc_free = sc_free; 9243abdb607SJ. Bruce Fields stid->sc_client = cl; 9253abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 9263abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 9273abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 928a15dfcd5SElena Reshetova refcount_set(&stid->sc_count, 1); 9299767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 930624322f1SOlga Kornievskaia INIT_LIST_HEAD(&stid->sc_cp_list); 9313abdb607SJ. Bruce Fields 932996e0938SJ. Bruce Fields /* 9333abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 9343abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 9353abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 9363abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 9373abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 9383abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 9393abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 940996e0938SJ. Bruce Fields */ 9413abdb607SJ. Bruce Fields return stid; 9423abdb607SJ. Bruce Fields out_free: 9432c44a234SWei Yongjun kmem_cache_free(slab, stid); 9443abdb607SJ. Bruce Fields return NULL; 9452a74aba7SJ. Bruce Fields } 9462a74aba7SJ. Bruce Fields 947e0639dc5SOlga Kornievskaia /* 948e0639dc5SOlga Kornievskaia * Create a unique stateid_t to represent each COPY. 949e0639dc5SOlga Kornievskaia */ 950624322f1SOlga Kornievskaia static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, 951624322f1SOlga Kornievskaia unsigned char sc_type) 952e0639dc5SOlga Kornievskaia { 953e0639dc5SOlga Kornievskaia int new_id; 954e0639dc5SOlga Kornievskaia 9559cc76801SArnd Bergmann stid->stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; 956624322f1SOlga Kornievskaia stid->stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; 957624322f1SOlga Kornievskaia stid->sc_type = sc_type; 958624322f1SOlga Kornievskaia 959e0639dc5SOlga Kornievskaia idr_preload(GFP_KERNEL); 960e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 961624322f1SOlga Kornievskaia new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT); 962624322f1SOlga Kornievskaia stid->stid.si_opaque.so_id = new_id; 963ca9364ddSDai Ngo stid->stid.si_generation = 1; 964e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 965e0639dc5SOlga Kornievskaia idr_preload_end(); 966e0639dc5SOlga Kornievskaia if (new_id < 0) 967e0639dc5SOlga Kornievskaia return 0; 968e0639dc5SOlga Kornievskaia return 1; 969e0639dc5SOlga Kornievskaia } 970e0639dc5SOlga Kornievskaia 971624322f1SOlga Kornievskaia int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy) 972624322f1SOlga Kornievskaia { 973624322f1SOlga Kornievskaia return nfs4_init_cp_state(nn, ©->cp_stateid, NFS4_COPY_STID); 974624322f1SOlga Kornievskaia } 975624322f1SOlga Kornievskaia 976624322f1SOlga Kornievskaia struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, 977624322f1SOlga Kornievskaia struct nfs4_stid *p_stid) 978624322f1SOlga Kornievskaia { 979624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 980624322f1SOlga Kornievskaia 981624322f1SOlga Kornievskaia cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL); 982624322f1SOlga Kornievskaia if (!cps) 983624322f1SOlga Kornievskaia return NULL; 98420b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 985624322f1SOlga Kornievskaia refcount_set(&cps->cp_stateid.sc_count, 1); 986624322f1SOlga Kornievskaia if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID)) 987624322f1SOlga Kornievskaia goto out_free; 988624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 989624322f1SOlga Kornievskaia list_add(&cps->cp_list, &p_stid->sc_cp_list); 990624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 991624322f1SOlga Kornievskaia return cps; 992624322f1SOlga Kornievskaia out_free: 993624322f1SOlga Kornievskaia kfree(cps); 994624322f1SOlga Kornievskaia return NULL; 995624322f1SOlga Kornievskaia } 996624322f1SOlga Kornievskaia 997624322f1SOlga Kornievskaia void nfs4_free_copy_state(struct nfsd4_copy *copy) 998e0639dc5SOlga Kornievskaia { 999e0639dc5SOlga Kornievskaia struct nfsd_net *nn; 1000e0639dc5SOlga Kornievskaia 1001624322f1SOlga Kornievskaia WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID); 1002e0639dc5SOlga Kornievskaia nn = net_generic(copy->cp_clp->net, nfsd_net_id); 1003e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1004624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 1005624322f1SOlga Kornievskaia copy->cp_stateid.stid.si_opaque.so_id); 1006624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1007624322f1SOlga Kornievskaia } 1008624322f1SOlga Kornievskaia 1009624322f1SOlga Kornievskaia static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid) 1010624322f1SOlga Kornievskaia { 1011624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 1012624322f1SOlga Kornievskaia struct nfsd_net *nn; 1013624322f1SOlga Kornievskaia 1014624322f1SOlga Kornievskaia nn = net_generic(net, nfsd_net_id); 1015624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1016624322f1SOlga Kornievskaia while (!list_empty(&stid->sc_cp_list)) { 1017624322f1SOlga Kornievskaia cps = list_first_entry(&stid->sc_cp_list, 1018624322f1SOlga Kornievskaia struct nfs4_cpntf_state, cp_list); 1019624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 1020624322f1SOlga Kornievskaia } 1021e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1022e0639dc5SOlga Kornievskaia } 1023e0639dc5SOlga Kornievskaia 1024b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 10254cdc951bSJ. Bruce Fields { 10266011695dSTrond Myklebust struct nfs4_stid *stid; 10276011695dSTrond Myklebust 1028d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 10296011695dSTrond Myklebust if (!stid) 10306011695dSTrond Myklebust return NULL; 10316011695dSTrond Myklebust 1032d19fb70dSKinglong Mee return openlockstateid(stid); 10336011695dSTrond Myklebust } 10346011695dSTrond Myklebust 10356011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 10366011695dSTrond Myklebust { 10376011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 10386011695dSTrond Myklebust atomic_long_dec(&num_delegations); 10394cdc951bSJ. Bruce Fields } 10404cdc951bSJ. Bruce Fields 10416282cd56SNeilBrown /* 10426282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 10436282cd56SNeilBrown * out again straight away. 10446282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 10456282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 10466282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 10476282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 10486282cd56SNeilBrown * filter. 10496282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 10506282cd56SNeilBrown * unless both are empty of course. 10516282cd56SNeilBrown * 10526282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 10536282cd56SNeilBrown * low 3 bytes as hash-table indices. 10546282cd56SNeilBrown * 1055f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 10566282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 10576282cd56SNeilBrown * except when swapping the two filters. 10586282cd56SNeilBrown */ 1059f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 10606282cd56SNeilBrown static struct bloom_pair { 10616282cd56SNeilBrown int entries, old_entries; 1062b3f255efSArnd Bergmann time64_t swap_time; 10636282cd56SNeilBrown int new; /* index into 'set' */ 10646282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 10656282cd56SNeilBrown } blocked_delegations; 10666282cd56SNeilBrown 10676282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 10686282cd56SNeilBrown { 10696282cd56SNeilBrown u32 hash; 10706282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 10716282cd56SNeilBrown 10726282cd56SNeilBrown if (bd->entries == 0) 10736282cd56SNeilBrown return 0; 1074b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 1075f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 1076b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 10776282cd56SNeilBrown bd->entries -= bd->old_entries; 10786282cd56SNeilBrown bd->old_entries = bd->entries; 10796282cd56SNeilBrown memset(bd->set[bd->new], 0, 10806282cd56SNeilBrown sizeof(bd->set[0])); 10816282cd56SNeilBrown bd->new = 1-bd->new; 1082b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 10836282cd56SNeilBrown } 1084f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 10856282cd56SNeilBrown } 1086d8b26071SNeilBrown hash = jhash(&fh->fh_raw, fh->fh_size, 0); 10876282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 10886282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 10896282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 10906282cd56SNeilBrown return 1; 10916282cd56SNeilBrown 10926282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 10936282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 10946282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 10956282cd56SNeilBrown return 1; 10966282cd56SNeilBrown 10976282cd56SNeilBrown return 0; 10986282cd56SNeilBrown } 10996282cd56SNeilBrown 11006282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 11016282cd56SNeilBrown { 11026282cd56SNeilBrown u32 hash; 11036282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 11046282cd56SNeilBrown 1105d8b26071SNeilBrown hash = jhash(&fh->fh_raw, fh->fh_size, 0); 11066282cd56SNeilBrown 1107f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 11086282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 11096282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 11106282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 11116282cd56SNeilBrown if (bd->entries == 0) 1112b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 11136282cd56SNeilBrown bd->entries += 1; 1114f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 11156282cd56SNeilBrown } 11166282cd56SNeilBrown 11171da177e4SLinus Torvalds static struct nfs4_delegation * 111886d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 111986d29b10SJ. Bruce Fields struct svc_fh *current_fh, 11208287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 11211da177e4SLinus Torvalds { 11221da177e4SLinus Torvalds struct nfs4_delegation *dp; 112302a3508dSTrond Myklebust long n; 11241da177e4SLinus Torvalds 11251da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 112602a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 112702a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 112802a3508dSTrond Myklebust goto out_dec; 11296282cd56SNeilBrown if (delegation_blocked(¤t_fh->fh_handle)) 113002a3508dSTrond Myklebust goto out_dec; 1131d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 11325b2d21c1SNeilBrown if (dp == NULL) 113302a3508dSTrond Myklebust goto out_dec; 11346011695dSTrond Myklebust 11352a74aba7SJ. Bruce Fields /* 11362a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 11376136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 11386136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 11392a74aba7SJ. Bruce Fields */ 11402a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 1141ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 1142ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 11431da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 11448287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 11458287f009SSachin Bhamare get_clnt_odstate(odstate); 114699c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 1147f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 114866af2579SDai Ngo dp->dl_recalled = false; 1149f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 11500162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 115186d29b10SJ. Bruce Fields get_nfs4_file(fp); 115286d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 11531da177e4SLinus Torvalds return dp; 115402a3508dSTrond Myklebust out_dec: 115502a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 115602a3508dSTrond Myklebust return NULL; 11571da177e4SLinus Torvalds } 11581da177e4SLinus Torvalds 11591da177e4SLinus Torvalds void 11606011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 11611da177e4SLinus Torvalds { 116211b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 11636011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 11646011695dSTrond Myklebust 11654770d722SJeff Layton might_lock(&clp->cl_lock); 11664770d722SJeff Layton 1167a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 1168b401be22SJeff Layton wake_up_all(&close_wq); 11696011695dSTrond Myklebust return; 1170b401be22SJeff Layton } 11716011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 1172624322f1SOlga Kornievskaia nfs4_free_cpntf_statelist(clp->net, s); 11734770d722SJeff Layton spin_unlock(&clp->cl_lock); 11746011695dSTrond Myklebust s->sc_free(s); 117511b9164aSTrond Myklebust if (fp) 117611b9164aSTrond Myklebust put_nfs4_file(fp); 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds 11799767feb2SJeff Layton void 11809767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 11819767feb2SJeff Layton { 11829767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 11839767feb2SJeff Layton 11849767feb2SJeff Layton spin_lock(&stid->sc_lock); 11859767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 11869767feb2SJeff Layton src->si_generation = 1; 11879767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 11889767feb2SJeff Layton spin_unlock(&stid->sc_lock); 11899767feb2SJeff Layton } 11909767feb2SJeff Layton 1191353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 11921da177e4SLinus Torvalds { 1193eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 1194353601e7SJ. Bruce Fields 1195353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 1196353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 1197eb82dd39SJeff Layton swap(nf, fp->fi_deleg_file); 1198353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 1199353601e7SJ. Bruce Fields 1200eb82dd39SJeff Layton if (nf) 1201eb82dd39SJeff Layton nfsd_file_put(nf); 1202353601e7SJ. Bruce Fields } 1203353601e7SJ. Bruce Fields 1204353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 1205353601e7SJ. Bruce Fields { 1206cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 1207eb82dd39SJeff Layton struct nfsd_file *nf = fp->fi_deleg_file; 1208417c6629SJeff Layton 1209b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 1210b8232d33SJ. Bruce Fields 1211eb82dd39SJeff Layton vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); 1212353601e7SJ. Bruce Fields put_deleg_file(fp); 12131da177e4SLinus Torvalds } 12141da177e4SLinus Torvalds 12150af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 12160af6e690SJ. Bruce Fields { 12170af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 1218353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 12190af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 12200af6e690SJ. Bruce Fields } 12210af6e690SJ. Bruce Fields 1222cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 12236136d2b4SJ. Bruce Fields { 12243abdb607SJ. Bruce Fields s->sc_type = 0; 12256136d2b4SJ. Bruce Fields } 12266136d2b4SJ. Bruce Fields 122734ed9872SAndrew Elble /** 122868b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 122934ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 123034ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 123134ed9872SAndrew Elble * 123234ed9872SAndrew Elble * Return: 123368b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 123434ed9872SAndrew Elble */ 123534ed9872SAndrew Elble 123668b18f52SJ. Bruce Fields static bool 123768b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 1238931ee56cSBenny Halevy { 123934ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 124034ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 124134ed9872SAndrew Elble 1242cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 1243417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 1244931ee56cSBenny Halevy 124534ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 124634ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 124734ed9872SAndrew Elble if (clp == searchclp) { 124851d87bc2SFengguang Wu return true; 124934ed9872SAndrew Elble } 125034ed9872SAndrew Elble } 125151d87bc2SFengguang Wu return false; 125234ed9872SAndrew Elble } 125334ed9872SAndrew Elble 125434ed9872SAndrew Elble /** 125534ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 125634ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 125734ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 125834ed9872SAndrew Elble * 125934ed9872SAndrew Elble * Return: 126034ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 126134ed9872SAndrew Elble * 126234ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 126334ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 126434ed9872SAndrew Elble * 126534ed9872SAndrew Elble */ 126634ed9872SAndrew Elble 126734ed9872SAndrew Elble static int 126834ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 126934ed9872SAndrew Elble { 127034ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 127134ed9872SAndrew Elble 127234ed9872SAndrew Elble lockdep_assert_held(&state_lock); 127334ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 127434ed9872SAndrew Elble 127568b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 127668b18f52SJ. Bruce Fields return -EAGAIN; 1277a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 12783fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 1279931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 128034ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 128134ed9872SAndrew Elble return 0; 1282931ee56cSBenny Halevy } 1283931ee56cSBenny Halevy 1284548ec080SJ. Bruce Fields static bool delegation_hashed(struct nfs4_delegation *dp) 1285548ec080SJ. Bruce Fields { 1286548ec080SJ. Bruce Fields return !(list_empty(&dp->dl_perfile)); 1287548ec080SJ. Bruce Fields } 1288548ec080SJ. Bruce Fields 12893fcbbd24SJeff Layton static bool 129042690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 12911da177e4SLinus Torvalds { 129211b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 129302e1215fSJeff Layton 129442690676SJeff Layton lockdep_assert_held(&state_lock); 129542690676SJeff Layton 1296548ec080SJ. Bruce Fields if (!delegation_hashed(dp)) 12973fcbbd24SJeff Layton return false; 12983fcbbd24SJeff Layton 1299b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 1300d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 1301d55a166cSJeff Layton ++dp->dl_time; 1302417c6629SJeff Layton spin_lock(&fp->fi_lock); 1303931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 13041da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 130502e1215fSJeff Layton list_del_init(&dp->dl_perfile); 130602e1215fSJeff Layton spin_unlock(&fp->fi_lock); 13073fcbbd24SJeff Layton return true; 1308cbf7a75bSJ. Bruce Fields } 13093bd64a5bSJ. Bruce Fields 13103bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 13113bd64a5bSJ. Bruce Fields { 13123fcbbd24SJeff Layton bool unhashed; 13133fcbbd24SJeff Layton 131442690676SJeff Layton spin_lock(&state_lock); 13153fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 131642690676SJeff Layton spin_unlock(&state_lock); 13170af6e690SJ. Bruce Fields if (unhashed) 13180af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 13193fcbbd24SJeff Layton } 13203bd64a5bSJ. Bruce Fields 13213bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 13223bd64a5bSJ. Bruce Fields { 13233bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 13243bd64a5bSJ. Bruce Fields 13252d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 13262d4a532dSJeff Layton 13270af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 13283bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 13290af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 13302d4a532dSJeff Layton spin_lock(&clp->cl_lock); 13312d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 13322d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 13333bd64a5bSJ. Bruce Fields } 13340af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 13353bd64a5bSJ. Bruce Fields } 13363bd64a5bSJ. Bruce Fields 13371da177e4SLinus Torvalds /* 13381da177e4SLinus Torvalds * SETCLIENTID state 13391da177e4SLinus Torvalds */ 13401da177e4SLinus Torvalds 1341ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1342ddc04c41SJ. Bruce Fields { 1343ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1344ddc04c41SJ. Bruce Fields } 1345ddc04c41SJ. Bruce Fields 13466b189105SScott Mayhew static unsigned int clientstr_hashval(struct xdr_netobj name) 1347ddc04c41SJ. Bruce Fields { 13486b189105SScott Mayhew return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; 1349ddc04c41SJ. Bruce Fields } 1350ddc04c41SJ. Bruce Fields 13511da177e4SLinus Torvalds /* 1352baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1353baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1354baeb4ff0SJeff Layton */ 1355baeb4ff0SJeff Layton static void 1356baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1357baeb4ff0SJeff Layton { 1358baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1359baeb4ff0SJeff Layton 1360baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1361baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1362baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1363baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1364baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1365baeb4ff0SJeff Layton } 1366baeb4ff0SJeff Layton 1367baeb4ff0SJeff Layton static void 1368baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1369baeb4ff0SJeff Layton { 1370baeb4ff0SJeff Layton int i; 1371baeb4ff0SJeff Layton bool change = false; 1372baeb4ff0SJeff Layton 1373baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1374baeb4ff0SJeff Layton if ((i & deny) != i) { 1375baeb4ff0SJeff Layton change = true; 1376baeb4ff0SJeff Layton clear_deny(i, stp); 1377baeb4ff0SJeff Layton } 1378baeb4ff0SJeff Layton } 1379baeb4ff0SJeff Layton 1380baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1381baeb4ff0SJeff Layton if (change) 138211b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1383baeb4ff0SJeff Layton } 1384baeb4ff0SJeff Layton 138582c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 138682c5ff1bSJeff Layton static void 138782c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 138882c5ff1bSJeff Layton { 138982c5ff1bSJeff Layton int i; 139011b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1391baeb4ff0SJeff Layton 1392baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1393baeb4ff0SJeff Layton recalculate_deny_mode(fp); 139482c5ff1bSJeff Layton 139582c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 139682c5ff1bSJeff Layton if (test_access(i, stp)) 139711b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 139882c5ff1bSJeff Layton clear_access(i, stp); 139982c5ff1bSJeff Layton } 140082c5ff1bSJeff Layton } 140182c5ff1bSJeff Layton 1402d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1403d50ffdedSKinglong Mee { 1404d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1405d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1406d50ffdedSKinglong Mee } 1407d50ffdedSKinglong Mee 14086b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 14096b180f0bSJeff Layton { 1410a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1411a819ecc1SJeff Layton 1412a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1413a819ecc1SJeff Layton 1414a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 14156b180f0bSJeff Layton return; 14168f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1417a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1418d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 14196b180f0bSJeff Layton } 14206b180f0bSJeff Layton 1421a451b123STrond Myklebust static bool 1422a451b123STrond Myklebust nfs4_ol_stateid_unhashed(const struct nfs4_ol_stateid *stp) 1423a451b123STrond Myklebust { 1424a451b123STrond Myklebust return list_empty(&stp->st_perfile); 1425a451b123STrond Myklebust } 1426a451b123STrond Myklebust 1427e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1428529d7b2aSJ. Bruce Fields { 142911b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 14301d31a253STrond Myklebust 14311c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 14321c755dc1SJeff Layton 1433e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1434e8568739SJeff Layton return false; 1435e8568739SJeff Layton 14361d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1437e8568739SJeff Layton list_del_init(&stp->st_perfile); 14381d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1439529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1440e8568739SJeff Layton return true; 1441529d7b2aSJ. Bruce Fields } 1442529d7b2aSJ. Bruce Fields 14436011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1444529d7b2aSJ. Bruce Fields { 14456011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 14464665e2baSJ. Bruce Fields 14478287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 14486011695dSTrond Myklebust release_all_access(stp); 1449d3134b10SJeff Layton if (stp->st_stateowner) 1450d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 14516011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1452529d7b2aSJ. Bruce Fields } 1453529d7b2aSJ. Bruce Fields 1454b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1455529d7b2aSJ. Bruce Fields { 1456b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1457b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1458eb82dd39SJeff Layton struct nfsd_file *nf; 1459529d7b2aSJ. Bruce Fields 1460eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 1461eb82dd39SJeff Layton if (nf) { 1462eb82dd39SJeff Layton get_file(nf->nf_file); 1463eb82dd39SJeff Layton filp_close(nf->nf_file, (fl_owner_t)lo); 1464eb82dd39SJeff Layton nfsd_file_put(nf); 1465eb82dd39SJeff Layton } 1466b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1467b49e084dSJeff Layton } 1468b49e084dSJeff Layton 14692c41beb0SJeff Layton /* 14702c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 14712c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 14722c41beb0SJeff Layton * reaplist for later destruction. 14732c41beb0SJeff Layton */ 14742c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 14752c41beb0SJeff Layton struct list_head *reaplist) 14762c41beb0SJeff Layton { 14772c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 14782c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 14792c41beb0SJeff Layton 14802c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 14812c41beb0SJeff Layton 14822c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 14832c41beb0SJeff Layton 1484a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 14852c41beb0SJeff Layton wake_up_all(&close_wq); 14862c41beb0SJeff Layton return; 14872c41beb0SJeff Layton } 14882c41beb0SJeff Layton 14892c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 14902c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 14912c41beb0SJeff Layton } 14922c41beb0SJeff Layton 1493e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 14943c1c995cSJeff Layton { 1495f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 14963c1c995cSJeff Layton 1497a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1498a451b123STrond Myklebust return false; 14993c1c995cSJeff Layton list_del_init(&stp->st_locks); 1500cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1501a451b123STrond Myklebust return true; 15023c1c995cSJeff Layton } 15033c1c995cSJeff Layton 15045adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1505b49e084dSJeff Layton { 1506f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1507e8568739SJeff Layton bool unhashed; 15081c755dc1SJeff Layton 1509f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1510e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1511f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1512e8568739SJeff Layton if (unhashed) 15136011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1514529d7b2aSJ. Bruce Fields } 1515529d7b2aSJ. Bruce Fields 1516c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1517529d7b2aSJ. Bruce Fields { 1518d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1519c58c6610STrond Myklebust 1520d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1521c58c6610STrond Myklebust 15228f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 15238f4b54c5SJeff Layton } 15248f4b54c5SJeff Layton 15252c41beb0SJeff Layton /* 15262c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 15272c41beb0SJeff Layton * fully unhashed. 15282c41beb0SJeff Layton */ 15292c41beb0SJeff Layton static void 15302c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 15312c41beb0SJeff Layton { 15322c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1533fb94d766SKinglong Mee struct nfs4_file *fp; 15342c41beb0SJeff Layton 15352c41beb0SJeff Layton might_sleep(); 15362c41beb0SJeff Layton 15372c41beb0SJeff Layton while (!list_empty(reaplist)) { 15382c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 15392c41beb0SJeff Layton st_locks); 15402c41beb0SJeff Layton list_del(&stp->st_locks); 1541fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 15422c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1543fb94d766SKinglong Mee if (fp) 1544fb94d766SKinglong Mee put_nfs4_file(fp); 15452c41beb0SJeff Layton } 15462c41beb0SJeff Layton } 15472c41beb0SJeff Layton 1548d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1549d83017f9SJeff Layton struct list_head *reaplist) 15503c87b9b7STrond Myklebust { 15513c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 15523c87b9b7STrond Myklebust 1553e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1554e8568739SJeff Layton 15553c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 15563c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 15573c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1558e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1559d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1560529d7b2aSJ. Bruce Fields } 1561529d7b2aSJ. Bruce Fields } 1562529d7b2aSJ. Bruce Fields 1563e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1564d83017f9SJeff Layton struct list_head *reaplist) 15652283963fSJ. Bruce Fields { 15662c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 15672c41beb0SJeff Layton 1568a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1569a451b123STrond Myklebust return false; 1570d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1571a451b123STrond Myklebust return true; 157238c387b5SJ. Bruce Fields } 157338c387b5SJ. Bruce Fields 157438c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 157538c387b5SJ. Bruce Fields { 15762c41beb0SJeff Layton LIST_HEAD(reaplist); 15772c41beb0SJeff Layton 15782c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1579e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 15802c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 15812c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 15822c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 15832283963fSJ. Bruce Fields } 15842283963fSJ. Bruce Fields 15857ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1586f1d110caSJ. Bruce Fields { 1587d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 15887ffb5880STrond Myklebust 1589d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 15907ffb5880STrond Myklebust 15918f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 15928f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1593f1d110caSJ. Bruce Fields } 1594f1d110caSJ. Bruce Fields 1595f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1596f7a4d872SJ. Bruce Fields { 1597217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1598217526e7SJeff Layton nfsd_net_id); 1599217526e7SJeff Layton struct nfs4_ol_stateid *s; 1600f7a4d872SJ. Bruce Fields 1601217526e7SJeff Layton spin_lock(&nn->client_lock); 1602217526e7SJeff Layton s = oo->oo_last_closed_stid; 1603f7a4d872SJ. Bruce Fields if (s) { 1604d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1605f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1606f7a4d872SJ. Bruce Fields } 1607217526e7SJeff Layton spin_unlock(&nn->client_lock); 1608217526e7SJeff Layton if (s) 1609217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1610f7a4d872SJ. Bruce Fields } 1611f7a4d872SJ. Bruce Fields 16122c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 16138f4b54c5SJeff Layton { 16148f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1615d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 16162c41beb0SJeff Layton struct list_head reaplist; 16177ffb5880STrond Myklebust 16182c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 16197ffb5880STrond Myklebust 1620d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 16217ffb5880STrond Myklebust unhash_openowner_locked(oo); 16222c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 16232c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 16242c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1625e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 16262c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 16272c41beb0SJeff Layton } 1628d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 16292c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1630f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 16316b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1632f1d110caSJ. Bruce Fields } 1633f1d110caSJ. Bruce Fields 16345282fd72SMarc Eshel static inline int 16355282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 16365282fd72SMarc Eshel { 16375282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 16385282fd72SMarc Eshel 16395282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 16405282fd72SMarc Eshel } 16415282fd72SMarc Eshel 1642135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 16435282fd72SMarc Eshel static inline void 16445282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 16455282fd72SMarc Eshel { 16465282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 16475282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 16485282fd72SMarc Eshel } 16498f199b82STrond Myklebust #else 16508f199b82STrond Myklebust static inline void 16518f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 16528f199b82STrond Myklebust { 16538f199b82STrond Myklebust } 16548f199b82STrond Myklebust #endif 16558f199b82STrond Myklebust 16569411b1d4SJ. Bruce Fields /* 16579411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 16589411b1d4SJ. Bruce Fields * won't be used for replay. 16599411b1d4SJ. Bruce Fields */ 16609411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 16619411b1d4SJ. Bruce Fields { 16629411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 16639411b1d4SJ. Bruce Fields 16649411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 16659411b1d4SJ. Bruce Fields return; 16669411b1d4SJ. Bruce Fields 16679411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 166858fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 16699411b1d4SJ. Bruce Fields return; 16709411b1d4SJ. Bruce Fields } 16719411b1d4SJ. Bruce Fields if (!so) 16729411b1d4SJ. Bruce Fields return; 16739411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 16749411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 16759411b1d4SJ. Bruce Fields so->so_seqid++; 16769411b1d4SJ. Bruce Fields return; 16779411b1d4SJ. Bruce Fields } 16785282fd72SMarc Eshel 1679ec6b5d7bSAndy Adamson static void 1680ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1681ec6b5d7bSAndy Adamson { 1682ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1683ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1684ec6b5d7bSAndy Adamson 1685ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1686ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1687ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1688ec6b5d7bSAndy Adamson sid->reserved = 0; 1689ec6b5d7bSAndy Adamson } 1690ec6b5d7bSAndy Adamson 1691ec6b5d7bSAndy Adamson /* 1692a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1693a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1694a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1695a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1696a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1697a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1698a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1699a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1700a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1701a649637cSAndy Adamson * for the SEQUENCE op response: 1702ec6b5d7bSAndy Adamson */ 1703a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1704a649637cSAndy Adamson 1705557ce264SAndy Adamson static void 1706557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1707557ce264SAndy Adamson { 1708557ce264SAndy Adamson int i; 1709557ce264SAndy Adamson 171053da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 171153da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1712557ce264SAndy Adamson kfree(ses->se_slots[i]); 1713557ce264SAndy Adamson } 171453da6a53SJ. Bruce Fields } 1715557ce264SAndy Adamson 1716efe0cb6dSJ. Bruce Fields /* 1717efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1718efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1719efe0cb6dSJ. Bruce Fields */ 172055c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1721efe0cb6dSJ. Bruce Fields { 172255c760cfSJ. Bruce Fields u32 size; 1723efe0cb6dSJ. Bruce Fields 172455c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 172555c760cfSJ. Bruce Fields size = 0; 172655c760cfSJ. Bruce Fields else 172755c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 172855c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1729557ce264SAndy Adamson } 1730557ce264SAndy Adamson 17315b6feee9SJ. Bruce Fields /* 17325b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 17335b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 173442b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 17355b6feee9SJ. Bruce Fields */ 17362030ca56SNeilBrown static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 17375b6feee9SJ. Bruce Fields { 173855c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 173955c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 1740c54f24e3SJ. Bruce Fields unsigned long avail, total_avail; 17412030ca56SNeilBrown unsigned int scale_factor; 17425b6feee9SJ. Bruce Fields 17435b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 17447f49fd5dSNeilBrown if (nfsd_drc_max_mem > nfsd_drc_mem_used) 1745c54f24e3SJ. Bruce Fields total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 17467f49fd5dSNeilBrown else 17477f49fd5dSNeilBrown /* We have handed out more space than we chose in 17487f49fd5dSNeilBrown * set_max_drc() to allow. That isn't really a 17497f49fd5dSNeilBrown * problem as long as that doesn't make us think we 17507f49fd5dSNeilBrown * have lots more due to integer overflow. 17517f49fd5dSNeilBrown */ 17527f49fd5dSNeilBrown total_avail = 0; 1753c54f24e3SJ. Bruce Fields avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1754de766e57SJ. Bruce Fields /* 17552030ca56SNeilBrown * Never use more than a fraction of the remaining memory, 17567f49fd5dSNeilBrown * unless it's the only way to give this client a slot. 17572030ca56SNeilBrown * The chosen fraction is either 1/8 or 1/number of threads, 17582030ca56SNeilBrown * whichever is smaller. This ensures there are adequate 17592030ca56SNeilBrown * slots to support multiple clients per thread. 17607f49fd5dSNeilBrown * Give the client one slot even if that would require 17617f49fd5dSNeilBrown * over-allocation--it is better than failure. 1762de766e57SJ. Bruce Fields */ 17632030ca56SNeilBrown scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); 17642030ca56SNeilBrown 17652030ca56SNeilBrown avail = clamp_t(unsigned long, avail, slotsize, 17662030ca56SNeilBrown total_avail/scale_factor); 17675b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 17687f49fd5dSNeilBrown num = max_t(int, num, 1); 17695b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 17705b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 17715b6feee9SJ. Bruce Fields 17725b6feee9SJ. Bruce Fields return num; 17735b6feee9SJ. Bruce Fields } 17745b6feee9SJ. Bruce Fields 177555c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 17765b6feee9SJ. Bruce Fields { 177755c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 177855c760cfSJ. Bruce Fields 17795b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 178055c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 17815b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 17825b6feee9SJ. Bruce Fields } 17835b6feee9SJ. Bruce Fields 178460810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 178560810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 17865b6feee9SJ. Bruce Fields { 178760810e54SKinglong Mee int numslots = fattrs->maxreqs; 178860810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 17895b6feee9SJ. Bruce Fields struct nfsd4_session *new; 17905b6feee9SJ. Bruce Fields int mem, i; 1791ec6b5d7bSAndy Adamson 1792c23753daSJ. Bruce Fields BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 1793ec6b5d7bSAndy Adamson + sizeof(struct nfsd4_session) > PAGE_SIZE); 17945b6feee9SJ. Bruce Fields mem = numslots * sizeof(struct nfsd4_slot *); 1795ec6b5d7bSAndy Adamson 17965b6feee9SJ. Bruce Fields new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); 17976c18ba9fSAlexandros Batsakis if (!new) 17985b6feee9SJ. Bruce Fields return NULL; 1799ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 18005b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 180155c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 18025b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1803ec6b5d7bSAndy Adamson goto out_free; 1804ec6b5d7bSAndy Adamson } 180560810e54SKinglong Mee 180660810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 180760810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 180860810e54SKinglong Mee 18095b6feee9SJ. Bruce Fields return new; 18105b6feee9SJ. Bruce Fields out_free: 18115b6feee9SJ. Bruce Fields while (i--) 18125b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 18135b6feee9SJ. Bruce Fields kfree(new); 18145b6feee9SJ. Bruce Fields return NULL; 18155b6feee9SJ. Bruce Fields } 18165b6feee9SJ. Bruce Fields 181719cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 181819cf5c02SJ. Bruce Fields { 181919cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 182019cf5c02SJ. Bruce Fields kfree(c); 182119cf5c02SJ. Bruce Fields } 182219cf5c02SJ. Bruce Fields 182319cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 182419cf5c02SJ. Bruce Fields { 182519cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 182619cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 182719cf5c02SJ. Bruce Fields 1828806d65b6SChuck Lever trace_nfsd_cb_lost(clp); 1829806d65b6SChuck Lever 183019cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 183119cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 183219cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 183319cf5c02SJ. Bruce Fields free_conn(c); 183419cf5c02SJ. Bruce Fields } 1835eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 18362e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 183719cf5c02SJ. Bruce Fields } 183819cf5c02SJ. Bruce Fields 1839d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1840c7662518SJ. Bruce Fields { 1841c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1842c7662518SJ. Bruce Fields 1843c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1844c7662518SJ. Bruce Fields if (!conn) 1845db90681dSJ. Bruce Fields return NULL; 1846c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1847c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1848d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1849db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1850db90681dSJ. Bruce Fields return conn; 1851db90681dSJ. Bruce Fields } 1852db90681dSJ. Bruce Fields 1853328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1854328ead28SJ. Bruce Fields { 1855328ead28SJ. Bruce Fields conn->cn_session = ses; 1856328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1857328ead28SJ. Bruce Fields } 1858328ead28SJ. Bruce Fields 1859db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1860db90681dSJ. Bruce Fields { 1861db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1862c7662518SJ. Bruce Fields 1863c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1864328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1865c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1866db90681dSJ. Bruce Fields } 1867c7662518SJ. Bruce Fields 186821b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1869db90681dSJ. Bruce Fields { 187019cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 187121b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1872db90681dSJ. Bruce Fields } 1873db90681dSJ. Bruce Fields 1874e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1875db90681dSJ. Bruce Fields { 187621b75b01SJ. Bruce Fields int ret; 1877db90681dSJ. Bruce Fields 1878db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 187921b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 188021b75b01SJ. Bruce Fields if (ret) 188121b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 188221b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 188357a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 188457a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1885c7662518SJ. Bruce Fields } 1886c7662518SJ. Bruce Fields 1887e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 18881d1bc8f2SJ. Bruce Fields { 18891d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 18901d1bc8f2SJ. Bruce Fields 1891e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 18921d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1893e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 18941d1bc8f2SJ. Bruce Fields } 18951d1bc8f2SJ. Bruce Fields 18961d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 189719cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1898c7662518SJ. Bruce Fields { 189919cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 190019cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 190119cf5c02SJ. Bruce Fields 190219cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 190319cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 190419cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 190519cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 190619cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 190719cf5c02SJ. Bruce Fields 190819cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 190919cf5c02SJ. Bruce Fields free_conn(c); 191019cf5c02SJ. Bruce Fields 191119cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 191219cf5c02SJ. Bruce Fields } 191319cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1914c7662518SJ. Bruce Fields } 1915c7662518SJ. Bruce Fields 19161377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 19171377b69eSJ. Bruce Fields { 19181377b69eSJ. Bruce Fields free_session_slots(ses); 19191377b69eSJ. Bruce Fields kfree(ses); 19201377b69eSJ. Bruce Fields } 19211377b69eSJ. Bruce Fields 192266b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1923508dc6e1SBenny Halevy { 1924c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 192555c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1926c7662518SJ. Bruce Fields __free_session(ses); 1927a827bcb2SJ. Bruce Fields } 1928ec6b5d7bSAndy Adamson 1929135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1930a827bcb2SJ. Bruce Fields { 1931a827bcb2SJ. Bruce Fields int idx; 19321872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1933a827bcb2SJ. Bruce Fields 1934ec6b5d7bSAndy Adamson new->se_client = clp; 1935ec6b5d7bSAndy Adamson gen_sessionid(new); 1936ec6b5d7bSAndy Adamson 1937c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1938c7662518SJ. Bruce Fields 1939ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1940ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 19418b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1942c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 194366b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 19445b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 19451872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 19464c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1947ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 19484c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 194960810e54SKinglong Mee 1950b0d2e42cSChuck Lever { 1951edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1952dcbeaa68SJ. Bruce Fields /* 1953dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1954dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1955dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1956dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1957dcbeaa68SJ. Bruce Fields * future: 1958dcbeaa68SJ. Bruce Fields */ 1959edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1960edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1961edd76786SJ. Bruce Fields } 1962ec6b5d7bSAndy Adamson } 1963ec6b5d7bSAndy Adamson 19649089f1b4SBenny Halevy /* caller must hold client_lock */ 19655282fd72SMarc Eshel static struct nfsd4_session * 1966d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 19675282fd72SMarc Eshel { 19685282fd72SMarc Eshel struct nfsd4_session *elem; 19695282fd72SMarc Eshel int idx; 19701872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 19715282fd72SMarc Eshel 19720a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 19730a880a28STrond Myklebust 19745282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 19755282fd72SMarc Eshel idx = hash_sessionid(sessionid); 19765282fd72SMarc Eshel /* Search in the appropriate list */ 19771872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 19785282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 19795282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 19805282fd72SMarc Eshel return elem; 19815282fd72SMarc Eshel } 19825282fd72SMarc Eshel } 19835282fd72SMarc Eshel 19845282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 19855282fd72SMarc Eshel return NULL; 19865282fd72SMarc Eshel } 19875282fd72SMarc Eshel 1988d4e19e70STrond Myklebust static struct nfsd4_session * 1989d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 1990d4e19e70STrond Myklebust __be32 *ret) 1991d4e19e70STrond Myklebust { 1992d4e19e70STrond Myklebust struct nfsd4_session *session; 1993d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 1994d4e19e70STrond Myklebust 1995d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 1996d4e19e70STrond Myklebust if (!session) 1997d4e19e70STrond Myklebust goto out; 1998d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 1999d4e19e70STrond Myklebust if (status) 2000d4e19e70STrond Myklebust session = NULL; 2001d4e19e70STrond Myklebust out: 2002d4e19e70STrond Myklebust *ret = status; 2003d4e19e70STrond Myklebust return session; 2004d4e19e70STrond Myklebust } 2005d4e19e70STrond Myklebust 20069089f1b4SBenny Halevy /* caller must hold client_lock */ 20077116ed6bSAndy Adamson static void 20085282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 20097116ed6bSAndy Adamson { 20100a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 20110a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20120a880a28STrond Myklebust 20130a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20140a880a28STrond Myklebust 20157116ed6bSAndy Adamson list_del(&ses->se_hash); 20164c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 20177116ed6bSAndy Adamson list_del(&ses->se_perclnt); 20184c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 20195282fd72SMarc Eshel } 20205282fd72SMarc Eshel 20211da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 20221da177e4SLinus Torvalds static int 20232c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 20241da177e4SLinus Torvalds { 2025bbc7f33aSJ. Bruce Fields /* 2026bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 2027bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 2028bbc7f33aSJ. Bruce Fields * a safe assumption: 2029bbc7f33aSJ. Bruce Fields */ 2030bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 20311da177e4SLinus Torvalds return 0; 2032dd5e3fbcSChuck Lever trace_nfsd_clid_stale(clid); 20331da177e4SLinus Torvalds return 1; 20341da177e4SLinus Torvalds } 20351da177e4SLinus Torvalds 20361da177e4SLinus Torvalds /* 20371da177e4SLinus Torvalds * XXX Should we use a slab cache ? 20381da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 20391da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 20401da177e4SLinus Torvalds */ 204135bba9a3SJ. Bruce Fields static struct nfs4_client *alloc_client(struct xdr_netobj name) 20421da177e4SLinus Torvalds { 20431da177e4SLinus Torvalds struct nfs4_client *clp; 2044d4f0489fSTrond Myklebust int i; 20451da177e4SLinus Torvalds 20469258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 204735bba9a3SJ. Bruce Fields if (clp == NULL) 204835bba9a3SJ. Bruce Fields return NULL; 20496f4859b8SJ. Bruce Fields xdr_netobj_dup(&clp->cl_name, &name, GFP_KERNEL); 2050d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 2051d4f0489fSTrond Myklebust goto err_no_name; 20526da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 20536da2ec56SKees Cook sizeof(struct list_head), 20546da2ec56SKees Cook GFP_KERNEL); 2055d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 2056d4f0489fSTrond Myklebust goto err_no_hashtbl; 2057d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 2058d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 20595694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 20605694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 206114ed14ccSJ. Bruce Fields atomic_set(&clp->cl_rpc_users, 0); 20625694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 206366af2579SDai Ngo clp->cl_state = NFSD4_ACTIVE; 206466af2579SDai Ngo atomic_set(&clp->cl_delegs_in_recall, 0); 20655694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 20665694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 20675694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 20685694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 20695694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 20709cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 20719cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 20729cf514ccSChristoph Hellwig #endif 2073e0639dc5SOlga Kornievskaia INIT_LIST_HEAD(&clp->async_copies); 2074e0639dc5SOlga Kornievskaia spin_lock_init(&clp->async_lock); 20755694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 20765694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 20771da177e4SLinus Torvalds return clp; 2078d4f0489fSTrond Myklebust err_no_hashtbl: 2079d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 2080d4f0489fSTrond Myklebust err_no_name: 20819258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 2082d4f0489fSTrond Myklebust return NULL; 20831da177e4SLinus Torvalds } 20841da177e4SLinus Torvalds 208559f8e91bSJ. Bruce Fields static void __free_client(struct kref *k) 208659f8e91bSJ. Bruce Fields { 2087e8a79fb1SJ. Bruce Fields struct nfsdfs_client *c = container_of(k, struct nfsdfs_client, cl_ref); 2088e8a79fb1SJ. Bruce Fields struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs); 208959f8e91bSJ. Bruce Fields 209059f8e91bSJ. Bruce Fields free_svc_cred(&clp->cl_cred); 209159f8e91bSJ. Bruce Fields kfree(clp->cl_ownerstr_hashtbl); 209259f8e91bSJ. Bruce Fields kfree(clp->cl_name.data); 209379123444SJ. Bruce Fields kfree(clp->cl_nii_domain.data); 209479123444SJ. Bruce Fields kfree(clp->cl_nii_name.data); 209559f8e91bSJ. Bruce Fields idr_destroy(&clp->cl_stateids); 209659f8e91bSJ. Bruce Fields kmem_cache_free(client_slab, clp); 209759f8e91bSJ. Bruce Fields } 209859f8e91bSJ. Bruce Fields 2099297e57a2SYueHaibing static void drop_client(struct nfs4_client *clp) 210059f8e91bSJ. Bruce Fields { 2101e8a79fb1SJ. Bruce Fields kref_put(&clp->cl_nfsdfs.cl_ref, __free_client); 210259f8e91bSJ. Bruce Fields } 210359f8e91bSJ. Bruce Fields 21044dd86e15STrond Myklebust static void 21051da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 21061da177e4SLinus Torvalds { 2107792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 2108792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2109792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 2110792c95ddSJ. Bruce Fields se_perclnt); 2111792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 211266b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 211366b2b9b2SJ. Bruce Fields free_session(ses); 2114792c95ddSJ. Bruce Fields } 21154cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 211689c905beSJ. Bruce Fields if (clp->cl_nfsd_dentry) { 2117e8a79fb1SJ. Bruce Fields nfsd_client_rmdir(clp->cl_nfsd_dentry); 211889c905beSJ. Bruce Fields clp->cl_nfsd_dentry = NULL; 211989c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 212089c905beSJ. Bruce Fields } 212159f8e91bSJ. Bruce Fields drop_client(clp); 21221da177e4SLinus Torvalds } 21231da177e4SLinus Torvalds 212484d38ac9SBenny Halevy /* must be called under the client_lock */ 21254beb345bSTrond Myklebust static void 212684d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 212784d38ac9SBenny Halevy { 21284beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2129792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2130792c95ddSJ. Bruce Fields 21310a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 21320a880a28STrond Myklebust 21334beb345bSTrond Myklebust /* Mark the client as expired! */ 21344beb345bSTrond Myklebust clp->cl_time = 0; 21354beb345bSTrond Myklebust /* Make it invisible */ 21364beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 21374beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 21384beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 21394beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 21404beb345bSTrond Myklebust else 21414beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 21424beb345bSTrond Myklebust } 21434beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 21444c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 2145792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 2146792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 21474c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 214884d38ac9SBenny Halevy } 214984d38ac9SBenny Halevy 21501da177e4SLinus Torvalds static void 21514beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 21524beb345bSTrond Myklebust { 21534beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 21544beb345bSTrond Myklebust 21554beb345bSTrond Myklebust spin_lock(&nn->client_lock); 21564beb345bSTrond Myklebust unhash_client_locked(clp); 21574beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 21584beb345bSTrond Myklebust } 21594beb345bSTrond Myklebust 216097403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 216197403d95SJeff Layton { 216214ed14ccSJ. Bruce Fields if (atomic_read(&clp->cl_rpc_users)) 216397403d95SJeff Layton return nfserr_jukebox; 216497403d95SJeff Layton unhash_client_locked(clp); 216597403d95SJeff Layton return nfs_ok; 216697403d95SJeff Layton } 216797403d95SJeff Layton 21684beb345bSTrond Myklebust static void 21694beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 21701da177e4SLinus Torvalds { 217168ef3bc3SJeff Layton int i; 2172fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 21731da177e4SLinus Torvalds struct nfs4_delegation *dp; 21741da177e4SLinus Torvalds struct list_head reaplist; 21751da177e4SLinus Torvalds 21761da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 2177cdc97505SBenny Halevy spin_lock(&state_lock); 2178ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 2179ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 21803fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 218142690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 21821da177e4SLinus Torvalds } 2183cdc97505SBenny Halevy spin_unlock(&state_lock); 21841da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 21851da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 218642690676SJeff Layton list_del_init(&dp->dl_recall_lru); 21870af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 21881da177e4SLinus Torvalds } 21892d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 2190c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 21912d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 21926011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 2193956c4feeSBenny Halevy } 2194ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 2195fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 2196b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 2197fe0750e5SJ. Bruce Fields release_openowner(oo); 21981da177e4SLinus Torvalds } 219968ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 220068ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 220168ef3bc3SJeff Layton 220268ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 220368ef3bc3SJeff Layton so_strhash) { 220468ef3bc3SJeff Layton /* Should be no openowners at this point */ 220568ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 220668ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 220768ef3bc3SJeff Layton } 220868ef3bc3SJeff Layton } 22099cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 2210e0639dc5SOlga Kornievskaia nfsd4_shutdown_copy(clp); 22116ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 22122bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 22132bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 2214b12a05cbSJ. Bruce Fields free_client(clp); 221589c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 22161da177e4SLinus Torvalds } 22171da177e4SLinus Torvalds 22184beb345bSTrond Myklebust static void 22194beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 22204beb345bSTrond Myklebust { 22214beb345bSTrond Myklebust unhash_client(clp); 22224beb345bSTrond Myklebust __destroy_client(clp); 22234beb345bSTrond Myklebust } 22244beb345bSTrond Myklebust 2225362063a5SScott Mayhew static void inc_reclaim_complete(struct nfs4_client *clp) 2226362063a5SScott Mayhew { 2227362063a5SScott Mayhew struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2228362063a5SScott Mayhew 2229362063a5SScott Mayhew if (!nn->track_reclaim_completes) 2230362063a5SScott Mayhew return; 2231362063a5SScott Mayhew if (!nfsd4_find_reclaim_client(clp->cl_name, nn)) 2232362063a5SScott Mayhew return; 2233362063a5SScott Mayhew if (atomic_inc_return(&nn->nr_reclaim_complete) == 2234362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) { 2235362063a5SScott Mayhew printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n", 2236362063a5SScott Mayhew clp->net->ns.inum); 2237362063a5SScott Mayhew nfsd4_end_grace(nn); 2238362063a5SScott Mayhew } 2239362063a5SScott Mayhew } 2240362063a5SScott Mayhew 22410d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 22420d22f68fSJ. Bruce Fields { 22434beb345bSTrond Myklebust unhash_client(clp); 22440d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 22454beb345bSTrond Myklebust __destroy_client(clp); 22460d22f68fSJ. Bruce Fields } 22470d22f68fSJ. Bruce Fields 224835bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 224935bba9a3SJ. Bruce Fields { 225035bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 225135bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 22521da177e4SLinus Torvalds } 22531da177e4SLinus Torvalds 225435bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 225535bba9a3SJ. Bruce Fields { 22561da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 22571da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 22581da177e4SLinus Torvalds } 22591da177e4SLinus Torvalds 226050043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 226150043859SJ. Bruce Fields { 22622f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 22632f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 22642f10fdcbSNeilBrown GFP_KERNEL); 22659abdda5dSChuck Lever target->cr_targ_princ = kstrdup(source->cr_targ_princ, GFP_KERNEL); 22662f10fdcbSNeilBrown if ((source->cr_principal && !target->cr_principal) || 22679abdda5dSChuck Lever (source->cr_raw_principal && !target->cr_raw_principal) || 22689abdda5dSChuck Lever (source->cr_targ_princ && !target->cr_targ_princ)) 22692f10fdcbSNeilBrown return -ENOMEM; 227050043859SJ. Bruce Fields 2271d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 22721da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 22731da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 22741da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 22751da177e4SLinus Torvalds get_group_info(target->cr_group_info); 22760dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 22770dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 22780dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 227903a4e1f6SJ. Bruce Fields return 0; 22801da177e4SLinus Torvalds } 22811da177e4SLinus Torvalds 2282ef17af2aSRasmus Villemoes static int 2283ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 2284ac55fdc4SJeff Layton { 2285ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2286ef17af2aSRasmus Villemoes return -1; 2287ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2288ef17af2aSRasmus Villemoes return 1; 2289ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2290ac55fdc4SJeff Layton } 2291ac55fdc4SJeff Layton 22921da177e4SLinus Torvalds static int 2293599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2294599e0a22SJ. Bruce Fields { 2295599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 22961da177e4SLinus Torvalds } 22971da177e4SLinus Torvalds 22981da177e4SLinus Torvalds static int 2299599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2300599e0a22SJ. Bruce Fields { 2301599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 23021da177e4SLinus Torvalds } 23031da177e4SLinus Torvalds 23048fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 23058fbba96eSJ. Bruce Fields { 23068fbba96eSJ. Bruce Fields int i; 23078fbba96eSJ. Bruce Fields 23088fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 23098fbba96eSJ. Bruce Fields return false; 23108fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 231181243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 23128fbba96eSJ. Bruce Fields return false; 23138fbba96eSJ. Bruce Fields return true; 23148fbba96eSJ. Bruce Fields } 23158fbba96eSJ. Bruce Fields 231668eb3508SJ. Bruce Fields /* 231768eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 231868eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 231968eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 232068eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 232168eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 232268eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 232368eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 232468eb3508SJ. Bruce Fields */ 232568eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 232668eb3508SJ. Bruce Fields { 232768eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 232868eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 232968eb3508SJ. Bruce Fields } 233068eb3508SJ. Bruce Fields 233168eb3508SJ. Bruce Fields 23325559b50aSVivek Trivedi static bool 2333599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2334599e0a22SJ. Bruce Fields { 233568eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 23366fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 23376fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 23388fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 23398fbba96eSJ. Bruce Fields return false; 23409abdda5dSChuck Lever /* XXX: check that cr_targ_princ fields match ? */ 23418fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 23428fbba96eSJ. Bruce Fields return true; 23438fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 23448fbba96eSJ. Bruce Fields return false; 23455559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 23461da177e4SLinus Torvalds } 23471da177e4SLinus Torvalds 234857266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 234957266a6eSJ. Bruce Fields { 235057266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 235157266a6eSJ. Bruce Fields u32 service; 235257266a6eSJ. Bruce Fields 2353c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2354c4720591SJ. Bruce Fields return false; 235557266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 235657266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 235757266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 235857266a6eSJ. Bruce Fields } 235957266a6eSJ. Bruce Fields 2360dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 236157266a6eSJ. Bruce Fields { 236257266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 236357266a6eSJ. Bruce Fields 236457266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 236557266a6eSJ. Bruce Fields return true; 236657266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 236757266a6eSJ. Bruce Fields return false; 236857266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 236957266a6eSJ. Bruce Fields return false; 2370414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2371414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2372414ca017SJ. Bruce Fields cr->cr_raw_principal); 237357266a6eSJ. Bruce Fields if (!cr->cr_principal) 237457266a6eSJ. Bruce Fields return false; 237557266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 237657266a6eSJ. Bruce Fields } 237757266a6eSJ. Bruce Fields 2378294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2379deda2faaSJ. Bruce Fields { 2380ab4684d1SChuck Lever __be32 verf[2]; 23811da177e4SLinus Torvalds 2382f419992cSJeff Layton /* 2383f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2384f419992cSJeff Layton * __force to keep sparse happy 2385f419992cSJeff Layton */ 23869104ae49SArnd Bergmann verf[0] = (__force __be32)(u32)ktime_get_real_seconds(); 238719311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2388ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 23891da177e4SLinus Torvalds } 23901da177e4SLinus Torvalds 2391294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2392294ac32eSJeff Layton { 23939cc76801SArnd Bergmann clp->cl_clientid.cl_boot = (u32)nn->boot_time; 2394294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2395294ac32eSJeff Layton gen_confirm(clp, nn); 2396294ac32eSJeff Layton } 2397294ac32eSJeff Layton 23984770d722SJeff Layton static struct nfs4_stid * 23994770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 24004581d140SJ. Bruce Fields { 24013abdb607SJ. Bruce Fields struct nfs4_stid *ret; 24023abdb607SJ. Bruce Fields 24033abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 24043abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 24053abdb607SJ. Bruce Fields return NULL; 24063abdb607SJ. Bruce Fields return ret; 24074581d140SJ. Bruce Fields } 24084d71ab87SJ. Bruce Fields 24094770d722SJeff Layton static struct nfs4_stid * 24104770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2411f459e453SJ. Bruce Fields { 2412f459e453SJ. Bruce Fields struct nfs4_stid *s; 2413f459e453SJ. Bruce Fields 24144770d722SJeff Layton spin_lock(&cl->cl_lock); 24154770d722SJeff Layton s = find_stateid_locked(cl, t); 24162d3f9668STrond Myklebust if (s != NULL) { 24172d3f9668STrond Myklebust if (typemask & s->sc_type) 2418a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 24192d3f9668STrond Myklebust else 24204770d722SJeff Layton s = NULL; 24212d3f9668STrond Myklebust } 24224770d722SJeff Layton spin_unlock(&cl->cl_lock); 24234d71ab87SJ. Bruce Fields return s; 24244581d140SJ. Bruce Fields } 24254581d140SJ. Bruce Fields 2426a204f25eSJ. Bruce Fields static struct nfs4_client *get_nfsdfs_clp(struct inode *inode) 2427a204f25eSJ. Bruce Fields { 2428a204f25eSJ. Bruce Fields struct nfsdfs_client *nc; 2429a204f25eSJ. Bruce Fields nc = get_nfsdfs_client(inode); 2430a204f25eSJ. Bruce Fields if (!nc) 2431a204f25eSJ. Bruce Fields return NULL; 2432a204f25eSJ. Bruce Fields return container_of(nc, struct nfs4_client, cl_nfsdfs); 2433a204f25eSJ. Bruce Fields } 2434a204f25eSJ. Bruce Fields 2435169319f1SJ. Bruce Fields static void seq_quote_mem(struct seq_file *m, char *data, int len) 2436169319f1SJ. Bruce Fields { 2437169319f1SJ. Bruce Fields seq_printf(m, "\""); 2438c0546391SAndy Shevchenko seq_escape_mem(m, data, len, ESCAPE_HEX | ESCAPE_NAP | ESCAPE_APPEND, "\"\\"); 2439169319f1SJ. Bruce Fields seq_printf(m, "\""); 2440169319f1SJ. Bruce Fields } 2441169319f1SJ. Bruce Fields 24423518c866SDave Wysochanski static const char *cb_state2str(int state) 24433518c866SDave Wysochanski { 24443518c866SDave Wysochanski switch (state) { 24453518c866SDave Wysochanski case NFSD4_CB_UP: 24463518c866SDave Wysochanski return "UP"; 24473518c866SDave Wysochanski case NFSD4_CB_UNKNOWN: 24483518c866SDave Wysochanski return "UNKNOWN"; 24493518c866SDave Wysochanski case NFSD4_CB_DOWN: 24503518c866SDave Wysochanski return "DOWN"; 24513518c866SDave Wysochanski case NFSD4_CB_FAULT: 24523518c866SDave Wysochanski return "FAULT"; 24533518c866SDave Wysochanski } 24543518c866SDave Wysochanski return "UNDEFINED"; 24553518c866SDave Wysochanski } 24563518c866SDave Wysochanski 245797ad4031SJ. Bruce Fields static int client_info_show(struct seq_file *m, void *v) 245897ad4031SJ. Bruce Fields { 245997ad4031SJ. Bruce Fields struct inode *inode = m->private; 246097ad4031SJ. Bruce Fields struct nfs4_client *clp; 246197ad4031SJ. Bruce Fields u64 clid; 246297ad4031SJ. Bruce Fields 2463a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2464a204f25eSJ. Bruce Fields if (!clp) 246597ad4031SJ. Bruce Fields return -ENXIO; 246697ad4031SJ. Bruce Fields memcpy(&clid, &clp->cl_clientid, sizeof(clid)); 246797ad4031SJ. Bruce Fields seq_printf(m, "clientid: 0x%llx\n", clid); 2468169319f1SJ. Bruce Fields seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); 2469472d155aSNeilBrown if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 2470472d155aSNeilBrown seq_puts(m, "status: confirmed\n"); 2471472d155aSNeilBrown else 2472472d155aSNeilBrown seq_puts(m, "status: unconfirmed\n"); 2473169319f1SJ. Bruce Fields seq_printf(m, "name: "); 2474169319f1SJ. Bruce Fields seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); 2475169319f1SJ. Bruce Fields seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); 247679123444SJ. Bruce Fields if (clp->cl_nii_domain.data) { 247779123444SJ. Bruce Fields seq_printf(m, "Implementation domain: "); 247879123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_domain.data, 247979123444SJ. Bruce Fields clp->cl_nii_domain.len); 248079123444SJ. Bruce Fields seq_printf(m, "\nImplementation name: "); 248179123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_name.data, clp->cl_nii_name.len); 2482e29f4703SArnd Bergmann seq_printf(m, "\nImplementation time: [%lld, %ld]\n", 248379123444SJ. Bruce Fields clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); 248479123444SJ. Bruce Fields } 24853518c866SDave Wysochanski seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state)); 24863518c866SDave Wysochanski seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr); 248797ad4031SJ. Bruce Fields drop_client(clp); 248897ad4031SJ. Bruce Fields 248997ad4031SJ. Bruce Fields return 0; 249097ad4031SJ. Bruce Fields } 249197ad4031SJ. Bruce Fields 249297ad4031SJ. Bruce Fields static int client_info_open(struct inode *inode, struct file *file) 249397ad4031SJ. Bruce Fields { 249497ad4031SJ. Bruce Fields return single_open(file, client_info_show, inode); 249597ad4031SJ. Bruce Fields } 249697ad4031SJ. Bruce Fields 249797ad4031SJ. Bruce Fields static const struct file_operations client_info_fops = { 249897ad4031SJ. Bruce Fields .open = client_info_open, 249997ad4031SJ. Bruce Fields .read = seq_read, 250097ad4031SJ. Bruce Fields .llseek = seq_lseek, 250197ad4031SJ. Bruce Fields .release = single_release, 250297ad4031SJ. Bruce Fields }; 250397ad4031SJ. Bruce Fields 250478599c42SJ. Bruce Fields static void *states_start(struct seq_file *s, loff_t *pos) 250578599c42SJ. Bruce Fields __acquires(&clp->cl_lock) 250678599c42SJ. Bruce Fields { 250778599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 250878599c42SJ. Bruce Fields unsigned long id = *pos; 250978599c42SJ. Bruce Fields void *ret; 251078599c42SJ. Bruce Fields 251178599c42SJ. Bruce Fields spin_lock(&clp->cl_lock); 251278599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 251378599c42SJ. Bruce Fields *pos = id; 251478599c42SJ. Bruce Fields return ret; 251578599c42SJ. Bruce Fields } 251678599c42SJ. Bruce Fields 251778599c42SJ. Bruce Fields static void *states_next(struct seq_file *s, void *v, loff_t *pos) 251878599c42SJ. Bruce Fields { 251978599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 252078599c42SJ. Bruce Fields unsigned long id = *pos; 252178599c42SJ. Bruce Fields void *ret; 252278599c42SJ. Bruce Fields 252378599c42SJ. Bruce Fields id = *pos; 252478599c42SJ. Bruce Fields id++; 252578599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 252678599c42SJ. Bruce Fields *pos = id; 252778599c42SJ. Bruce Fields return ret; 252878599c42SJ. Bruce Fields } 252978599c42SJ. Bruce Fields 253078599c42SJ. Bruce Fields static void states_stop(struct seq_file *s, void *v) 253178599c42SJ. Bruce Fields __releases(&clp->cl_lock) 253278599c42SJ. Bruce Fields { 253378599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 253478599c42SJ. Bruce Fields 253578599c42SJ. Bruce Fields spin_unlock(&clp->cl_lock); 253678599c42SJ. Bruce Fields } 253778599c42SJ. Bruce Fields 2538580da465SAchilles Gaikwad static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f) 2539580da465SAchilles Gaikwad { 2540580da465SAchilles Gaikwad seq_printf(s, "filename: \"%pD2\"", f->nf_file); 2541580da465SAchilles Gaikwad } 2542580da465SAchilles Gaikwad 2543fd4f83fdSJeff Layton static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) 254478599c42SJ. Bruce Fields { 2545fd4f83fdSJeff Layton struct inode *inode = f->nf_inode; 254678599c42SJ. Bruce Fields 254778599c42SJ. Bruce Fields seq_printf(s, "superblock: \"%02x:%02x:%ld\"", 254878599c42SJ. Bruce Fields MAJOR(inode->i_sb->s_dev), 254978599c42SJ. Bruce Fields MINOR(inode->i_sb->s_dev), 255078599c42SJ. Bruce Fields inode->i_ino); 255178599c42SJ. Bruce Fields } 255278599c42SJ. Bruce Fields 255378599c42SJ. Bruce Fields static void nfs4_show_owner(struct seq_file *s, struct nfs4_stateowner *oo) 255478599c42SJ. Bruce Fields { 255578599c42SJ. Bruce Fields seq_printf(s, "owner: "); 255678599c42SJ. Bruce Fields seq_quote_mem(s, oo->so_owner.data, oo->so_owner.len); 255778599c42SJ. Bruce Fields } 255878599c42SJ. Bruce Fields 2559ace7ade4SJ. Bruce Fields static void nfs4_show_stateid(struct seq_file *s, stateid_t *stid) 2560ace7ade4SJ. Bruce Fields { 2561ee590d25SJ. Bruce Fields seq_printf(s, "0x%.8x", stid->si_generation); 2562ee590d25SJ. Bruce Fields seq_printf(s, "%12phN", &stid->si_opaque); 2563ace7ade4SJ. Bruce Fields } 2564ace7ade4SJ. Bruce Fields 256578599c42SJ. Bruce Fields static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) 256678599c42SJ. Bruce Fields { 256778599c42SJ. Bruce Fields struct nfs4_ol_stateid *ols; 256878599c42SJ. Bruce Fields struct nfs4_file *nf; 2569fd4f83fdSJeff Layton struct nfsd_file *file; 257078599c42SJ. Bruce Fields struct nfs4_stateowner *oo; 257178599c42SJ. Bruce Fields unsigned int access, deny; 257278599c42SJ. Bruce Fields 257378599c42SJ. Bruce Fields if (st->sc_type != NFS4_OPEN_STID && st->sc_type != NFS4_LOCK_STID) 257478599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 257578599c42SJ. Bruce Fields ols = openlockstateid(st); 257678599c42SJ. Bruce Fields oo = ols->st_stateowner; 257778599c42SJ. Bruce Fields nf = st->sc_file; 257878599c42SJ. Bruce Fields file = find_any_file(nf); 25799affa435SJ. Bruce Fields if (!file) 25809affa435SJ. Bruce Fields return 0; 258178599c42SJ. Bruce Fields 2582ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2583ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2584ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: open, "); 258578599c42SJ. Bruce Fields 258678599c42SJ. Bruce Fields access = bmap_to_share_mode(ols->st_access_bmap); 258778599c42SJ. Bruce Fields deny = bmap_to_share_mode(ols->st_deny_bmap); 258878599c42SJ. Bruce Fields 2589c4b77edbSJ. Bruce Fields seq_printf(s, "access: %s%s, ", 259078599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_READ ? "r" : "-", 259178599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 2592c4b77edbSJ. Bruce Fields seq_printf(s, "deny: %s%s, ", 259378599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", 259478599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 259578599c42SJ. Bruce Fields 259678599c42SJ. Bruce Fields nfs4_show_superblock(s, file); 259778599c42SJ. Bruce Fields seq_printf(s, ", "); 2598580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2599580da465SAchilles Gaikwad seq_printf(s, ", "); 260078599c42SJ. Bruce Fields nfs4_show_owner(s, oo); 260178599c42SJ. Bruce Fields seq_printf(s, " }\n"); 2602fd4f83fdSJeff Layton nfsd_file_put(file); 260378599c42SJ. Bruce Fields 260478599c42SJ. Bruce Fields return 0; 260578599c42SJ. Bruce Fields } 260678599c42SJ. Bruce Fields 260716d36e09SJ. Bruce Fields static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) 260816d36e09SJ. Bruce Fields { 260916d36e09SJ. Bruce Fields struct nfs4_ol_stateid *ols; 261016d36e09SJ. Bruce Fields struct nfs4_file *nf; 2611fd4f83fdSJeff Layton struct nfsd_file *file; 261216d36e09SJ. Bruce Fields struct nfs4_stateowner *oo; 261316d36e09SJ. Bruce Fields 261416d36e09SJ. Bruce Fields ols = openlockstateid(st); 261516d36e09SJ. Bruce Fields oo = ols->st_stateowner; 261616d36e09SJ. Bruce Fields nf = st->sc_file; 261716d36e09SJ. Bruce Fields file = find_any_file(nf); 26189affa435SJ. Bruce Fields if (!file) 26199affa435SJ. Bruce Fields return 0; 262016d36e09SJ. Bruce Fields 2621ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2622ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2623ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: lock, "); 262416d36e09SJ. Bruce Fields 262516d36e09SJ. Bruce Fields /* 262616d36e09SJ. Bruce Fields * Note: a lock stateid isn't really the same thing as a lock, 262716d36e09SJ. Bruce Fields * it's the locking state held by one owner on a file, and there 262816d36e09SJ. Bruce Fields * may be multiple (or no) lock ranges associated with it. 262916d36e09SJ. Bruce Fields * (Same for the matter is true of open stateids.) 263016d36e09SJ. Bruce Fields */ 263116d36e09SJ. Bruce Fields 263216d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 263316d36e09SJ. Bruce Fields /* XXX: open stateid? */ 263416d36e09SJ. Bruce Fields seq_printf(s, ", "); 2635580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2636580da465SAchilles Gaikwad seq_printf(s, ", "); 263716d36e09SJ. Bruce Fields nfs4_show_owner(s, oo); 263816d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2639fd4f83fdSJeff Layton nfsd_file_put(file); 264016d36e09SJ. Bruce Fields 264116d36e09SJ. Bruce Fields return 0; 264216d36e09SJ. Bruce Fields } 264316d36e09SJ. Bruce Fields 264416d36e09SJ. Bruce Fields static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) 264516d36e09SJ. Bruce Fields { 264616d36e09SJ. Bruce Fields struct nfs4_delegation *ds; 264716d36e09SJ. Bruce Fields struct nfs4_file *nf; 2648eb82dd39SJeff Layton struct nfsd_file *file; 264916d36e09SJ. Bruce Fields 265016d36e09SJ. Bruce Fields ds = delegstateid(st); 265116d36e09SJ. Bruce Fields nf = st->sc_file; 26529affa435SJ. Bruce Fields file = find_deleg_file(nf); 26539affa435SJ. Bruce Fields if (!file) 26549affa435SJ. Bruce Fields return 0; 265516d36e09SJ. Bruce Fields 2656ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2657ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2658ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: deleg, "); 265916d36e09SJ. Bruce Fields 266016d36e09SJ. Bruce Fields /* Kinda dead code as long as we only support read delegs: */ 266116d36e09SJ. Bruce Fields seq_printf(s, "access: %s, ", 266216d36e09SJ. Bruce Fields ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); 266316d36e09SJ. Bruce Fields 266416d36e09SJ. Bruce Fields /* XXX: lease time, whether it's being recalled. */ 266516d36e09SJ. Bruce Fields 266616d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 2667580da465SAchilles Gaikwad seq_printf(s, ", "); 2668580da465SAchilles Gaikwad nfs4_show_fname(s, file); 266916d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 26709affa435SJ. Bruce Fields nfsd_file_put(file); 267116d36e09SJ. Bruce Fields 267216d36e09SJ. Bruce Fields return 0; 267316d36e09SJ. Bruce Fields } 267416d36e09SJ. Bruce Fields 26750c4b62b0SJ. Bruce Fields static int nfs4_show_layout(struct seq_file *s, struct nfs4_stid *st) 26760c4b62b0SJ. Bruce Fields { 26770c4b62b0SJ. Bruce Fields struct nfs4_layout_stateid *ls; 2678eb82dd39SJeff Layton struct nfsd_file *file; 26790c4b62b0SJ. Bruce Fields 26800c4b62b0SJ. Bruce Fields ls = container_of(st, struct nfs4_layout_stateid, ls_stid); 26810c4b62b0SJ. Bruce Fields file = ls->ls_file; 26820c4b62b0SJ. Bruce Fields 2683ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2684ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2685ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: layout, "); 26860c4b62b0SJ. Bruce Fields 26870c4b62b0SJ. Bruce Fields /* XXX: What else would be useful? */ 26880c4b62b0SJ. Bruce Fields 26890c4b62b0SJ. Bruce Fields nfs4_show_superblock(s, file); 2690580da465SAchilles Gaikwad seq_printf(s, ", "); 2691580da465SAchilles Gaikwad nfs4_show_fname(s, file); 26920c4b62b0SJ. Bruce Fields seq_printf(s, " }\n"); 26930c4b62b0SJ. Bruce Fields 26940c4b62b0SJ. Bruce Fields return 0; 26950c4b62b0SJ. Bruce Fields } 26960c4b62b0SJ. Bruce Fields 269778599c42SJ. Bruce Fields static int states_show(struct seq_file *s, void *v) 269878599c42SJ. Bruce Fields { 269978599c42SJ. Bruce Fields struct nfs4_stid *st = v; 270078599c42SJ. Bruce Fields 270178599c42SJ. Bruce Fields switch (st->sc_type) { 270278599c42SJ. Bruce Fields case NFS4_OPEN_STID: 270378599c42SJ. Bruce Fields return nfs4_show_open(s, st); 270416d36e09SJ. Bruce Fields case NFS4_LOCK_STID: 270516d36e09SJ. Bruce Fields return nfs4_show_lock(s, st); 270616d36e09SJ. Bruce Fields case NFS4_DELEG_STID: 270716d36e09SJ. Bruce Fields return nfs4_show_deleg(s, st); 27080c4b62b0SJ. Bruce Fields case NFS4_LAYOUT_STID: 27090c4b62b0SJ. Bruce Fields return nfs4_show_layout(s, st); 271078599c42SJ. Bruce Fields default: 271178599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 271278599c42SJ. Bruce Fields } 271316d36e09SJ. Bruce Fields /* XXX: copy stateids? */ 271478599c42SJ. Bruce Fields } 271578599c42SJ. Bruce Fields 271678599c42SJ. Bruce Fields static struct seq_operations states_seq_ops = { 271778599c42SJ. Bruce Fields .start = states_start, 271878599c42SJ. Bruce Fields .next = states_next, 271978599c42SJ. Bruce Fields .stop = states_stop, 272078599c42SJ. Bruce Fields .show = states_show 272178599c42SJ. Bruce Fields }; 272278599c42SJ. Bruce Fields 272378599c42SJ. Bruce Fields static int client_states_open(struct inode *inode, struct file *file) 272478599c42SJ. Bruce Fields { 272578599c42SJ. Bruce Fields struct seq_file *s; 272678599c42SJ. Bruce Fields struct nfs4_client *clp; 272778599c42SJ. Bruce Fields int ret; 272878599c42SJ. Bruce Fields 2729a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2730a204f25eSJ. Bruce Fields if (!clp) 273178599c42SJ. Bruce Fields return -ENXIO; 273278599c42SJ. Bruce Fields 273378599c42SJ. Bruce Fields ret = seq_open(file, &states_seq_ops); 273478599c42SJ. Bruce Fields if (ret) 273578599c42SJ. Bruce Fields return ret; 273678599c42SJ. Bruce Fields s = file->private_data; 273778599c42SJ. Bruce Fields s->private = clp; 273878599c42SJ. Bruce Fields return 0; 273978599c42SJ. Bruce Fields } 274078599c42SJ. Bruce Fields 274178599c42SJ. Bruce Fields static int client_opens_release(struct inode *inode, struct file *file) 274278599c42SJ. Bruce Fields { 274378599c42SJ. Bruce Fields struct seq_file *m = file->private_data; 274478599c42SJ. Bruce Fields struct nfs4_client *clp = m->private; 274578599c42SJ. Bruce Fields 274678599c42SJ. Bruce Fields /* XXX: alternatively, we could get/drop in seq start/stop */ 274778599c42SJ. Bruce Fields drop_client(clp); 274878599c42SJ. Bruce Fields return 0; 274978599c42SJ. Bruce Fields } 275078599c42SJ. Bruce Fields 275178599c42SJ. Bruce Fields static const struct file_operations client_states_fops = { 275278599c42SJ. Bruce Fields .open = client_states_open, 275378599c42SJ. Bruce Fields .read = seq_read, 275478599c42SJ. Bruce Fields .llseek = seq_lseek, 275578599c42SJ. Bruce Fields .release = client_opens_release, 275678599c42SJ. Bruce Fields }; 275778599c42SJ. Bruce Fields 275889c905beSJ. Bruce Fields /* 275989c905beSJ. Bruce Fields * Normally we refuse to destroy clients that are in use, but here the 276089c905beSJ. Bruce Fields * administrator is telling us to just do it. We also want to wait 276189c905beSJ. Bruce Fields * so the caller has a guarantee that the client's locks are gone by 276289c905beSJ. Bruce Fields * the time the write returns: 276389c905beSJ. Bruce Fields */ 2764297e57a2SYueHaibing static void force_expire_client(struct nfs4_client *clp) 276589c905beSJ. Bruce Fields { 276689c905beSJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 276789c905beSJ. Bruce Fields bool already_expired; 276889c905beSJ. Bruce Fields 27692958d2eeSChuck Lever trace_nfsd_clid_admin_expired(&clp->cl_clientid); 27702958d2eeSChuck Lever 2771f7104cc1SJ. Bruce Fields spin_lock(&nn->client_lock); 277289c905beSJ. Bruce Fields clp->cl_time = 0; 2773f7104cc1SJ. Bruce Fields spin_unlock(&nn->client_lock); 277489c905beSJ. Bruce Fields 277589c905beSJ. Bruce Fields wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0); 277689c905beSJ. Bruce Fields spin_lock(&nn->client_lock); 277789c905beSJ. Bruce Fields already_expired = list_empty(&clp->cl_lru); 277889c905beSJ. Bruce Fields if (!already_expired) 277989c905beSJ. Bruce Fields unhash_client_locked(clp); 278089c905beSJ. Bruce Fields spin_unlock(&nn->client_lock); 278189c905beSJ. Bruce Fields 278289c905beSJ. Bruce Fields if (!already_expired) 278389c905beSJ. Bruce Fields expire_client(clp); 278489c905beSJ. Bruce Fields else 278589c905beSJ. Bruce Fields wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL); 278689c905beSJ. Bruce Fields } 278789c905beSJ. Bruce Fields 278889c905beSJ. Bruce Fields static ssize_t client_ctl_write(struct file *file, const char __user *buf, 278989c905beSJ. Bruce Fields size_t size, loff_t *pos) 279089c905beSJ. Bruce Fields { 279189c905beSJ. Bruce Fields char *data; 279289c905beSJ. Bruce Fields struct nfs4_client *clp; 279389c905beSJ. Bruce Fields 279489c905beSJ. Bruce Fields data = simple_transaction_get(file, buf, size); 279589c905beSJ. Bruce Fields if (IS_ERR(data)) 279689c905beSJ. Bruce Fields return PTR_ERR(data); 279789c905beSJ. Bruce Fields if (size != 7 || 0 != memcmp(data, "expire\n", 7)) 279889c905beSJ. Bruce Fields return -EINVAL; 279989c905beSJ. Bruce Fields clp = get_nfsdfs_clp(file_inode(file)); 280089c905beSJ. Bruce Fields if (!clp) 280189c905beSJ. Bruce Fields return -ENXIO; 280289c905beSJ. Bruce Fields force_expire_client(clp); 280389c905beSJ. Bruce Fields drop_client(clp); 280489c905beSJ. Bruce Fields return 7; 280589c905beSJ. Bruce Fields } 280689c905beSJ. Bruce Fields 280789c905beSJ. Bruce Fields static const struct file_operations client_ctl_fops = { 280889c905beSJ. Bruce Fields .write = client_ctl_write, 280989c905beSJ. Bruce Fields .release = simple_transaction_release, 281089c905beSJ. Bruce Fields }; 281189c905beSJ. Bruce Fields 281297ad4031SJ. Bruce Fields static const struct tree_descr client_files[] = { 281397ad4031SJ. Bruce Fields [0] = {"info", &client_info_fops, S_IRUSR}, 281478599c42SJ. Bruce Fields [1] = {"states", &client_states_fops, S_IRUSR}, 28156cbfad5fSPetr Vorel [2] = {"ctl", &client_ctl_fops, S_IWUSR}, 281678599c42SJ. Bruce Fields [3] = {""}, 281797ad4031SJ. Bruce Fields }; 281897ad4031SJ. Bruce Fields 28192216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2820b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2821b09333c4SRicardo Labiaga { 2822b09333c4SRicardo Labiaga struct nfs4_client *clp; 2823b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 282403a4e1f6SJ. Bruce Fields int ret; 2825c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2826e8a79fb1SJ. Bruce Fields struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2827472d155aSNeilBrown struct dentry *dentries[ARRAY_SIZE(client_files)]; 2828b09333c4SRicardo Labiaga 2829b09333c4SRicardo Labiaga clp = alloc_client(name); 2830b09333c4SRicardo Labiaga if (clp == NULL) 2831b09333c4SRicardo Labiaga return NULL; 2832b09333c4SRicardo Labiaga 283303a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 283403a4e1f6SJ. Bruce Fields if (ret) { 2835b09333c4SRicardo Labiaga free_client(clp); 2836b09333c4SRicardo Labiaga return NULL; 2837b09333c4SRicardo Labiaga } 2838e8a79fb1SJ. Bruce Fields gen_clid(clp, nn); 2839e8a79fb1SJ. Bruce Fields kref_init(&clp->cl_nfsdfs.cl_ref); 28400162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 284120b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 2842b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2843b09333c4SRicardo Labiaga copy_verf(clp, verf); 28443bade247SJ. Bruce Fields memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); 2845edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2846c212cecfSStanislav Kinsbursky clp->net = net; 2847472d155aSNeilBrown clp->cl_nfsd_dentry = nfsd_client_mkdir( 2848472d155aSNeilBrown nn, &clp->cl_nfsdfs, 284997ad4031SJ. Bruce Fields clp->cl_clientid.cl_id - nn->clientid_base, 2850472d155aSNeilBrown client_files, dentries); 2851472d155aSNeilBrown clp->cl_nfsd_info_dentry = dentries[0]; 2852e8a79fb1SJ. Bruce Fields if (!clp->cl_nfsd_dentry) { 2853e8a79fb1SJ. Bruce Fields free_client(clp); 2854e8a79fb1SJ. Bruce Fields return NULL; 2855e8a79fb1SJ. Bruce Fields } 2856b09333c4SRicardo Labiaga return clp; 2857b09333c4SRicardo Labiaga } 2858b09333c4SRicardo Labiaga 2859fd39ca9aSNeilBrown static void 2860ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2861ac55fdc4SJeff Layton { 2862ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2863ac55fdc4SJeff Layton struct nfs4_client *clp; 2864ac55fdc4SJeff Layton 2865ac55fdc4SJeff Layton while (*new) { 2866ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2867ac55fdc4SJeff Layton parent = *new; 2868ac55fdc4SJeff Layton 2869ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2870ac55fdc4SJeff Layton new = &((*new)->rb_left); 2871ac55fdc4SJeff Layton else 2872ac55fdc4SJeff Layton new = &((*new)->rb_right); 2873ac55fdc4SJeff Layton } 2874ac55fdc4SJeff Layton 2875ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2876ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2877ac55fdc4SJeff Layton } 2878ac55fdc4SJeff Layton 2879ac55fdc4SJeff Layton static struct nfs4_client * 2880ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2881ac55fdc4SJeff Layton { 2882ef17af2aSRasmus Villemoes int cmp; 2883ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2884ac55fdc4SJeff Layton struct nfs4_client *clp; 2885ac55fdc4SJeff Layton 2886ac55fdc4SJeff Layton while (node) { 2887ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2888ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2889ac55fdc4SJeff Layton if (cmp > 0) 2890ac55fdc4SJeff Layton node = node->rb_left; 2891ac55fdc4SJeff Layton else if (cmp < 0) 2892ac55fdc4SJeff Layton node = node->rb_right; 2893ac55fdc4SJeff Layton else 2894ac55fdc4SJeff Layton return clp; 2895ac55fdc4SJeff Layton } 2896ac55fdc4SJeff Layton return NULL; 2897ac55fdc4SJeff Layton } 2898ac55fdc4SJeff Layton 2899ac55fdc4SJeff Layton static void 2900ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 29011da177e4SLinus Torvalds { 29021da177e4SLinus Torvalds unsigned int idhashval; 29030a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 29041da177e4SLinus Torvalds 29050a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 29060a880a28STrond Myklebust 2907ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2908a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 29091da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 29100a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 29113dbacee6STrond Myklebust renew_client_locked(clp); 29121da177e4SLinus Torvalds } 29131da177e4SLinus Torvalds 2914fd39ca9aSNeilBrown static void 29151da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 29161da177e4SLinus Torvalds { 29171da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 29188daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 29191da177e4SLinus Torvalds 29200a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 29210a880a28STrond Myklebust 29228daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 2923a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 2924382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 2925934bd07fSJ. Bruce Fields set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 29267e3b32acSChuck Lever trace_nfsd_clid_confirmed(&clp->cl_clientid); 29273dbacee6STrond Myklebust renew_client_locked(clp); 29281da177e4SLinus Torvalds } 29291da177e4SLinus Torvalds 29301da177e4SLinus Torvalds static struct nfs4_client * 2931bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 29321da177e4SLinus Torvalds { 29331da177e4SLinus Torvalds struct nfs4_client *clp; 29341da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 29351da177e4SLinus Torvalds 2936bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 2937a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 2938d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 2939d15c077eSJ. Bruce Fields return NULL; 29403dbacee6STrond Myklebust renew_client_locked(clp); 29411da177e4SLinus Torvalds return clp; 29421da177e4SLinus Torvalds } 2943a50d2ad1SJ. Bruce Fields } 29441da177e4SLinus Torvalds return NULL; 29451da177e4SLinus Torvalds } 29461da177e4SLinus Torvalds 29471da177e4SLinus Torvalds static struct nfs4_client * 2948bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 2949bfa85e83SJ. Bruce Fields { 2950bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 2951bfa85e83SJ. Bruce Fields 29520a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2953bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 2954bfa85e83SJ. Bruce Fields } 2955bfa85e83SJ. Bruce Fields 2956bfa85e83SJ. Bruce Fields static struct nfs4_client * 29570a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 29581da177e4SLinus Torvalds { 2959bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 29601da177e4SLinus Torvalds 29610a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2962bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 29631da177e4SLinus Torvalds } 29641da177e4SLinus Torvalds 29656e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 2966a1bcecd2SAndy Adamson { 29676e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 2968a1bcecd2SAndy Adamson } 2969a1bcecd2SAndy Adamson 297028ce6054SNeilBrown static struct nfs4_client * 2971382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 297228ce6054SNeilBrown { 29730a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2974382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 297528ce6054SNeilBrown } 297628ce6054SNeilBrown 297728ce6054SNeilBrown static struct nfs4_client * 2978a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 297928ce6054SNeilBrown { 29800a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2981a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 298228ce6054SNeilBrown } 298328ce6054SNeilBrown 2984fd39ca9aSNeilBrown static void 29856f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 29861da177e4SLinus Torvalds { 298707263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 29886f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 29896f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 29907077ecbaSJeff Layton unsigned short expected_family; 29911da177e4SLinus Torvalds 29927077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 29937077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 29947077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 29957077ecbaSJeff Layton expected_family = AF_INET; 29967077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 29977077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 29987077ecbaSJeff Layton expected_family = AF_INET6; 29997077ecbaSJeff Layton else 30001da177e4SLinus Torvalds goto out_err; 30011da177e4SLinus Torvalds 3002c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 3003aa9a4ec7SJeff Layton se->se_callback_addr_len, 300407263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 300507263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 3006aa9a4ec7SJeff Layton 300707263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 30081da177e4SLinus Torvalds goto out_err; 3009aa9a4ec7SJeff Layton 301007263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 301107263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 3012fbf4665fSJeff Layton 301307263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 301407263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 3015849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 30161eace0d1SChuck Lever trace_nfsd_cb_args(clp, conn); 30171da177e4SLinus Torvalds return; 30181da177e4SLinus Torvalds out_err: 301907263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 302007263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 30211eace0d1SChuck Lever trace_nfsd_cb_nodelegs(clp); 30221da177e4SLinus Torvalds return; 30231da177e4SLinus Torvalds } 30241da177e4SLinus Torvalds 3025074fe897SAndy Adamson /* 3026067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 3027074fe897SAndy Adamson */ 3028b607664eSTrond Myklebust static void 3029074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 3030074fe897SAndy Adamson { 3031bddfdbcdSChuck Lever struct xdr_buf *buf = resp->xdr->buf; 3032557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3033557ce264SAndy Adamson unsigned int base; 3034074fe897SAndy Adamson 3035557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 3036074fe897SAndy Adamson 3037085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 3038557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 3039557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 304053da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 304153da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 3042bf864a31SAndy Adamson 3043085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 3044085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 3045bf864a31SAndy Adamson return; 3046bf864a31SAndy Adamson } 3047085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 3048085def3aSJ. Bruce Fields 3049f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 3050f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 3051f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 3052d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 3053d3f03403SDan Carpenter __func__); 3054557ce264SAndy Adamson return; 3055074fe897SAndy Adamson } 3056074fe897SAndy Adamson 3057074fe897SAndy Adamson /* 3058abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 3059abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 3060abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 3061abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 3062abfabf8cSAndy Adamson * 3063074fe897SAndy Adamson */ 3064abfabf8cSAndy Adamson static __be32 3065abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 3066abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 3067074fe897SAndy Adamson { 3068abfabf8cSAndy Adamson struct nfsd4_op *op; 3069abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3070074fe897SAndy Adamson 3071abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 3072abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 3073abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 3074abfabf8cSAndy Adamson 3075085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 3076085def3aSJ. Bruce Fields return op->status; 3077085def3aSJ. Bruce Fields if (args->opcnt == 1) { 3078085def3aSJ. Bruce Fields /* 3079085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 3080085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 3081085def3aSJ. Bruce Fields * original: 3082085def3aSJ. Bruce Fields */ 3083085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 3084085def3aSJ. Bruce Fields } else { 3085abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 3086abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 3087abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 3088074fe897SAndy Adamson } 3089abfabf8cSAndy Adamson return op->status; 3090074fe897SAndy Adamson } 3091074fe897SAndy Adamson 3092074fe897SAndy Adamson /* 3093557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 3094557ce264SAndy Adamson * session values. 3095074fe897SAndy Adamson */ 30963ca2eb98SJ. Bruce Fields static __be32 3097bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 3098bf864a31SAndy Adamson struct nfsd4_sequence *seq) 3099074fe897SAndy Adamson { 3100557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3101bddfdbcdSChuck Lever struct xdr_stream *xdr = resp->xdr; 3102f5236013SJ. Bruce Fields __be32 *p; 3103074fe897SAndy Adamson __be32 status; 3104074fe897SAndy Adamson 3105557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 3106074fe897SAndy Adamson 3107abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 31080da7b19cSJ. Bruce Fields if (status) 3109abfabf8cSAndy Adamson return status; 3110074fe897SAndy Adamson 3111f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 3112f5236013SJ. Bruce Fields if (!p) { 3113f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 3114f5236013SJ. Bruce Fields return nfserr_serverfault; 3115f5236013SJ. Bruce Fields } 3116f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 3117f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 3118074fe897SAndy Adamson 3119557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 3120f5236013SJ. Bruce Fields return slot->sl_status; 3121074fe897SAndy Adamson } 3122074fe897SAndy Adamson 31230733d213SAndy Adamson /* 31240733d213SAndy Adamson * Set the exchange_id flags returned by the server. 31250733d213SAndy Adamson */ 31260733d213SAndy Adamson static void 31270733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 31280733d213SAndy Adamson { 31299cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 31309cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 31319cf514ccSChristoph Hellwig #else 31320733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 31339cf514ccSChristoph Hellwig #endif 31340733d213SAndy Adamson 31350733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 31360733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 31370733d213SAndy Adamson 31380733d213SAndy Adamson /* set the wire flags to return to client. */ 31390733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 31400733d213SAndy Adamson } 31410733d213SAndy Adamson 31424eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 31434eaea134SJ. Bruce Fields { 31444eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 31454eaea134SJ. Bruce Fields 31464eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 31474eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 31484eaea134SJ. Bruce Fields return true; 31494eaea134SJ. Bruce Fields } 31504eaea134SJ. Bruce Fields return false; 31514eaea134SJ. Bruce Fields } 31524eaea134SJ. Bruce Fields 3153631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 3154631fc9eaSJ. Bruce Fields { 31554eaea134SJ. Bruce Fields return client_has_openowners(clp) 315647e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 315747e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 315847e970beSKinglong Mee #endif 31596eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 3160e0639dc5SOlga Kornievskaia || !list_empty(&clp->cl_sessions) 3161e0639dc5SOlga Kornievskaia || !list_empty(&clp->async_copies); 3162631fc9eaSJ. Bruce Fields } 3163631fc9eaSJ. Bruce Fields 316479123444SJ. Bruce Fields static __be32 copy_impl_id(struct nfs4_client *clp, 316579123444SJ. Bruce Fields struct nfsd4_exchange_id *exid) 316679123444SJ. Bruce Fields { 316779123444SJ. Bruce Fields if (!exid->nii_domain.data) 316879123444SJ. Bruce Fields return 0; 316979123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_domain, &exid->nii_domain, GFP_KERNEL); 317079123444SJ. Bruce Fields if (!clp->cl_nii_domain.data) 317179123444SJ. Bruce Fields return nfserr_jukebox; 317279123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_name, &exid->nii_name, GFP_KERNEL); 317379123444SJ. Bruce Fields if (!clp->cl_nii_name.data) 317479123444SJ. Bruce Fields return nfserr_jukebox; 3175e29f4703SArnd Bergmann clp->cl_nii_time = exid->nii_time; 317679123444SJ. Bruce Fields return 0; 317779123444SJ. Bruce Fields } 317879123444SJ. Bruce Fields 3179b37ad28bSAl Viro __be32 3180eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3181eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3182069b6ad4SAndy Adamson { 3183eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 31843dbacee6STrond Myklebust struct nfs4_client *conf, *new; 31853dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 318657b7b43bSJ. Bruce Fields __be32 status; 3187363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 31880733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 3189363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 319083e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 3191c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 31920733d213SAndy Adamson 3193363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 31940733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 3195523ec6edSChuck Lever "ip_addr=%s flags %x, spa_how %u\n", 31960733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 3197363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 31980733d213SAndy Adamson 3199a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 32000733d213SAndy Adamson return nfserr_inval; 32010733d213SAndy Adamson 320250c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 320350c7b948SJ. Bruce Fields if (new == NULL) 320450c7b948SJ. Bruce Fields return nfserr_jukebox; 320579123444SJ. Bruce Fields status = copy_impl_id(new, exid); 320679123444SJ. Bruce Fields if (status) 320779123444SJ. Bruce Fields goto out_nolock; 320850c7b948SJ. Bruce Fields 32090733d213SAndy Adamson switch (exid->spa_how) { 321057266a6eSJ. Bruce Fields case SP4_MACH_CRED: 3211ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 3212ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 3213ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 3214ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 3215ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 3216ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 3217ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 3218ed941643SAndrew Elble 3219ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 3220ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 3221ed941643SAndrew Elble 1 << (OP_LOCKU) | 3222ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 3223ed941643SAndrew Elble 3224ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 3225ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 3226ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 322750c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 322850c7b948SJ. Bruce Fields status = nfserr_inval; 322950c7b948SJ. Bruce Fields goto out_nolock; 323050c7b948SJ. Bruce Fields } 3231920dd9bbSJ. Bruce Fields /* 3232920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 3233920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 3234920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 3235920dd9bbSJ. Bruce Fields */ 3236414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 3237414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 3238920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 3239920dd9bbSJ. Bruce Fields goto out_nolock; 3240920dd9bbSJ. Bruce Fields } 324150c7b948SJ. Bruce Fields new->cl_mach_cred = true; 324276c50eb7SGustavo A. R. Silva break; 32430733d213SAndy Adamson case SP4_NONE: 32440733d213SAndy Adamson break; 3245063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 3246063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 3247df561f66SGustavo A. R. Silva fallthrough; 32480733d213SAndy Adamson case SP4_SSV: 32498edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 32508edf4b02SKinglong Mee goto out_nolock; 32510733d213SAndy Adamson } 32520733d213SAndy Adamson 32532dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 32543dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3255382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 32560733d213SAndy Adamson if (conf) { 325783e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 325883e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 325983e08fd4SJ. Bruce Fields 3260136e658dSJ. Bruce Fields if (update) { 3261136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 32622dbb269dSJ. Bruce Fields status = nfserr_inval; 3263e203d506SJ. Bruce Fields goto out; 3264e203d506SJ. Bruce Fields } 3265dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 326657266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 326757266a6eSJ. Bruce Fields goto out; 326857266a6eSJ. Bruce Fields } 32692dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 32700733d213SAndy Adamson status = nfserr_perm; 32710733d213SAndy Adamson goto out; 32720733d213SAndy Adamson } 32732dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 32740733d213SAndy Adamson status = nfserr_not_same; 32750733d213SAndy Adamson goto out; 32760733d213SAndy Adamson } 3277136e658dSJ. Bruce Fields /* case 6 */ 32780733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 3279e8f80c55SChuck Lever trace_nfsd_clid_confirmed_r(conf); 32800733d213SAndy Adamson goto out_copy; 32816ddbbbfeSMike Sager } 3282136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 3283631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 3284136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 328527787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 3286136e658dSJ. Bruce Fields goto out; 3287136e658dSJ. Bruce Fields } 3288b9831b59SJ. Bruce Fields goto out_new; 3289631fc9eaSJ. Bruce Fields } 3290136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 32910f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 3292e8f80c55SChuck Lever trace_nfsd_clid_confirmed_r(conf); 3293136e658dSJ. Bruce Fields goto out_copy; 3294136e658dSJ. Bruce Fields } 32952dbb269dSJ. Bruce Fields /* case 5, client reboot */ 3296744ea54cSChuck Lever trace_nfsd_clid_verf_mismatch(conf, rqstp, &verf); 32973dbacee6STrond Myklebust conf = NULL; 32980733d213SAndy Adamson goto out_new; 32990733d213SAndy Adamson } 33006ddbbbfeSMike Sager 33012dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 33020733d213SAndy Adamson status = nfserr_noent; 33030733d213SAndy Adamson goto out; 33040733d213SAndy Adamson } 33050733d213SAndy Adamson 3306a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 33072dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 33083dbacee6STrond Myklebust unhash_client_locked(unconf); 33090733d213SAndy Adamson 3310e8f80c55SChuck Lever /* case 1, new owner ID */ 3311e8f80c55SChuck Lever trace_nfsd_clid_fresh(new); 3312e8f80c55SChuck Lever 33130733d213SAndy Adamson out_new: 3314fd699b8aSJeff Layton if (conf) { 3315fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3316fd699b8aSJeff Layton if (status) 3317fd699b8aSJeff Layton goto out; 33182958d2eeSChuck Lever trace_nfsd_clid_replaced(&conf->cl_clientid); 3319fd699b8aSJeff Layton } 33204f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 3321ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 3322ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 33230733d213SAndy Adamson 3324ac55fdc4SJeff Layton add_to_unconfirmed(new); 33253dbacee6STrond Myklebust swap(new, conf); 33260733d213SAndy Adamson out_copy: 33275cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 33285cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 33290733d213SAndy Adamson 33305cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 33315cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 33320733d213SAndy Adamson 33330733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 33345cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 33350733d213SAndy Adamson status = nfs_ok; 33360733d213SAndy Adamson 33370733d213SAndy Adamson out: 33383dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 333950c7b948SJ. Bruce Fields out_nolock: 33405cc40fd7STrond Myklebust if (new) 33413dbacee6STrond Myklebust expire_client(new); 3342e8f80c55SChuck Lever if (unconf) { 3343e8f80c55SChuck Lever trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); 33443dbacee6STrond Myklebust expire_client(unconf); 3345e8f80c55SChuck Lever } 33460733d213SAndy Adamson return status; 3347069b6ad4SAndy Adamson } 3348069b6ad4SAndy Adamson 334957b7b43bSJ. Bruce Fields static __be32 335088e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 3351b85d4c01SBenny Halevy { 335288e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 335388e588d5SAndy Adamson slot_seqid); 3354b85d4c01SBenny Halevy 3355b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 335688e588d5SAndy Adamson if (slot_inuse) { 335788e588d5SAndy Adamson if (seqid == slot_seqid) 3358b85d4c01SBenny Halevy return nfserr_jukebox; 3359b85d4c01SBenny Halevy else 3360b85d4c01SBenny Halevy return nfserr_seq_misordered; 3361b85d4c01SBenny Halevy } 3362f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 336388e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 3364b85d4c01SBenny Halevy return nfs_ok; 336588e588d5SAndy Adamson if (seqid == slot_seqid) 3366b85d4c01SBenny Halevy return nfserr_replay_cache; 3367b85d4c01SBenny Halevy return nfserr_seq_misordered; 3368b85d4c01SBenny Halevy } 3369b85d4c01SBenny Halevy 337049557cc7SAndy Adamson /* 337149557cc7SAndy Adamson * Cache the create session result into the create session single DRC 337249557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 337349557cc7SAndy Adamson * Do this for solo or embedded create session operations. 337449557cc7SAndy Adamson */ 337549557cc7SAndy Adamson static void 337649557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 337757b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 337849557cc7SAndy Adamson { 337949557cc7SAndy Adamson slot->sl_status = nfserr; 338049557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 338149557cc7SAndy Adamson } 338249557cc7SAndy Adamson 338349557cc7SAndy Adamson static __be32 338449557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 338549557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 338649557cc7SAndy Adamson { 338749557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 338849557cc7SAndy Adamson return slot->sl_status; 338949557cc7SAndy Adamson } 339049557cc7SAndy Adamson 33911b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 33921b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 33931b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 33941b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 33951b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 33961b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 33971b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 33981b74c25bSMi Jinlong 33991b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 34001b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 34011b74c25bSMi Jinlong 1 + /* status */ \ 34021b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 34031b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 34041b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 34051b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 34061b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 34071b74c25bSMi Jinlong 340855c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 34091b74c25bSMi Jinlong { 341055c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 341155c760cfSJ. Bruce Fields 3412373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 3413373cd409SJ. Bruce Fields return nfserr_toosmall; 3414373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 3415373cd409SJ. Bruce Fields return nfserr_toosmall; 341655c760cfSJ. Bruce Fields ca->headerpadsz = 0; 341755c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 341855c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 341955c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 342055c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 342155c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 342255c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 342355c760cfSJ. Bruce Fields /* 342455c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 342555c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 342655c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 342755c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 342855c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 342955c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 34307f49fd5dSNeilBrown * Note that we always allow at least one slot, because our 34317f49fd5dSNeilBrown * accounting is soft and provides no guarantees either way. 343255c760cfSJ. Bruce Fields */ 34332030ca56SNeilBrown ca->maxreqs = nfsd4_get_drc_mem(ca, nn); 343455c760cfSJ. Bruce Fields 3435373cd409SJ. Bruce Fields return nfs_ok; 34361b74c25bSMi Jinlong } 34371b74c25bSMi Jinlong 34384500632fSChuck Lever /* 34394500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 34404500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 34414500632fSChuck Lever */ 34424500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 34434500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 34444500632fSChuck Lever 34454500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 34464500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 34474500632fSChuck Lever 34488a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 34494500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 34508a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 34514500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 34524500632fSChuck Lever sizeof(__be32)) 34538a891633SKinglong Mee 345406b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 345506b332a5SJ. Bruce Fields { 345606b332a5SJ. Bruce Fields ca->headerpadsz = 0; 345706b332a5SJ. Bruce Fields 34588a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 345906b332a5SJ. Bruce Fields return nfserr_toosmall; 34608a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 346106b332a5SJ. Bruce Fields return nfserr_toosmall; 346206b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 346306b332a5SJ. Bruce Fields if (ca->maxops < 2) 346406b332a5SJ. Bruce Fields return nfserr_toosmall; 346506b332a5SJ. Bruce Fields 346606b332a5SJ. Bruce Fields return nfs_ok; 3467069b6ad4SAndy Adamson } 3468069b6ad4SAndy Adamson 3469b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 3470b78724b7SJ. Bruce Fields { 3471b78724b7SJ. Bruce Fields switch (cbs->flavor) { 3472b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 3473b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 3474b78724b7SJ. Bruce Fields return nfs_ok; 3475b78724b7SJ. Bruce Fields default: 3476b78724b7SJ. Bruce Fields /* 3477b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 3478b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 3479b78724b7SJ. Bruce Fields * GSS. 3480b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 3481b78724b7SJ. Bruce Fields * client might think it can already handle: 3482b78724b7SJ. Bruce Fields */ 3483b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 3484b78724b7SJ. Bruce Fields } 3485b78724b7SJ. Bruce Fields } 3486b78724b7SJ. Bruce Fields 3487069b6ad4SAndy Adamson __be32 3488069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 3489eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 3490069b6ad4SAndy Adamson { 3491eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 3492363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 3493ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 3494d20c11d8SJeff Layton struct nfs4_client *old = NULL; 3495ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 349681f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 349749557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 349857b7b43bSJ. Bruce Fields __be32 status = 0; 34998daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3500ec6b5d7bSAndy Adamson 3501a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 3502a62573dcSMi Jinlong return nfserr_inval; 3503b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 3504b78724b7SJ. Bruce Fields if (status) 3505b78724b7SJ. Bruce Fields return status; 350655c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 3507373cd409SJ. Bruce Fields if (status) 3508373cd409SJ. Bruce Fields return status; 350906b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 351006b332a5SJ. Bruce Fields if (status) 3511f403e450SKinglong Mee goto out_release_drc_mem; 351281f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 351360810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 351455c760cfSJ. Bruce Fields if (!new) 351555c760cfSJ. Bruce Fields goto out_release_drc_mem; 351681f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 351781f0b2a4SJ. Bruce Fields if (!conn) 351881f0b2a4SJ. Bruce Fields goto out_free_session; 3519a62573dcSMi Jinlong 3520d20c11d8SJeff Layton spin_lock(&nn->client_lock); 35210a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 35228daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 352378389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3524ec6b5d7bSAndy Adamson 3525ec6b5d7bSAndy Adamson if (conf) { 352657266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3527dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 352857266a6eSJ. Bruce Fields goto out_free_conn; 352949557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 353049557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 3531f5e22bb6SKinglong Mee if (status) { 3532f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 353349557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 353481f0b2a4SJ. Bruce Fields goto out_free_conn; 3535ec6b5d7bSAndy Adamson } 3536ec6b5d7bSAndy Adamson } else if (unconf) { 353727787733SChuck Lever status = nfserr_clid_inuse; 3538ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 3539363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 354027787733SChuck Lever trace_nfsd_clid_cred_mismatch(unconf, rqstp); 354181f0b2a4SJ. Bruce Fields goto out_free_conn; 3542ec6b5d7bSAndy Adamson } 354357266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3544dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 354557266a6eSJ. Bruce Fields goto out_free_conn; 354649557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 354749557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 354838eb76a5SAndy Adamson if (status) { 354938eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 3550ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 355181f0b2a4SJ. Bruce Fields goto out_free_conn; 3552ec6b5d7bSAndy Adamson } 3553382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3554221a6876SJ. Bruce Fields if (old) { 3555d20c11d8SJeff Layton status = mark_client_expired_locked(old); 35567abea1e8SJeff Layton if (status) { 35577abea1e8SJeff Layton old = NULL; 3558221a6876SJ. Bruce Fields goto out_free_conn; 3559221a6876SJ. Bruce Fields } 35602958d2eeSChuck Lever trace_nfsd_clid_replaced(&old->cl_clientid); 35617abea1e8SJeff Layton } 35628f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 3563ec6b5d7bSAndy Adamson conf = unconf; 3564ec6b5d7bSAndy Adamson } else { 3565ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 356681f0b2a4SJ. Bruce Fields goto out_free_conn; 3567ec6b5d7bSAndy Adamson } 356881f0b2a4SJ. Bruce Fields status = nfs_ok; 35694ce85c8cSChuck Lever /* Persistent sessions are not supported */ 3570408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 35714ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 3572408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 3573408b79bcSJ. Bruce Fields 357481f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 3575d20c11d8SJeff Layton nfsd4_get_session_locked(new); 357681f0b2a4SJ. Bruce Fields 3577ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 3578ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 357986c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 358049557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 3581ec6b5d7bSAndy Adamson 3582d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 358349557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 3584d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3585934bd07fSJ. Bruce Fields if (conf == unconf) 3586934bd07fSJ. Bruce Fields fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); 3587d20c11d8SJeff Layton /* init connection and backchannel */ 3588d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 3589d20c11d8SJeff Layton nfsd4_put_session(new); 3590d20c11d8SJeff Layton if (old) 3591d20c11d8SJeff Layton expire_client(old); 3592ec6b5d7bSAndy Adamson return status; 359381f0b2a4SJ. Bruce Fields out_free_conn: 3594d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 359581f0b2a4SJ. Bruce Fields free_conn(conn); 3596d20c11d8SJeff Layton if (old) 3597d20c11d8SJeff Layton expire_client(old); 359881f0b2a4SJ. Bruce Fields out_free_session: 359981f0b2a4SJ. Bruce Fields __free_session(new); 360055c760cfSJ. Bruce Fields out_release_drc_mem: 360155c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 36021ca50792SJ. Bruce Fields return status; 3603069b6ad4SAndy Adamson } 3604069b6ad4SAndy Adamson 36051d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 36061d1bc8f2SJ. Bruce Fields { 36071d1bc8f2SJ. Bruce Fields switch (*dir) { 36081d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 36091d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 36101d1bc8f2SJ. Bruce Fields return nfs_ok; 36111d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 36121d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 36131d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 36141d1bc8f2SJ. Bruce Fields return nfs_ok; 3615fc5fc5d7Szhengbin } 36161d1bc8f2SJ. Bruce Fields return nfserr_inval; 36171d1bc8f2SJ. Bruce Fields } 36181d1bc8f2SJ. Bruce Fields 3619eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 3620eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3621eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3622cb73a9f4SJ. Bruce Fields { 3623eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 3624cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 3625c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3626b78724b7SJ. Bruce Fields __be32 status; 3627cb73a9f4SJ. Bruce Fields 3628b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 3629b78724b7SJ. Bruce Fields if (status) 3630b78724b7SJ. Bruce Fields return status; 3631c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3632cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 3633cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 3634c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3635cb73a9f4SJ. Bruce Fields 3636cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 3637cb73a9f4SJ. Bruce Fields 3638cb73a9f4SJ. Bruce Fields return nfs_ok; 3639cb73a9f4SJ. Bruce Fields } 3640cb73a9f4SJ. Bruce Fields 3641c2d715a1SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3642c2d715a1SJ. Bruce Fields { 3643c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3644c2d715a1SJ. Bruce Fields 3645c2d715a1SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3646c2d715a1SJ. Bruce Fields if (c->cn_xprt == xpt) { 3647c2d715a1SJ. Bruce Fields return c; 3648c2d715a1SJ. Bruce Fields } 3649c2d715a1SJ. Bruce Fields } 3650c2d715a1SJ. Bruce Fields return NULL; 3651c2d715a1SJ. Bruce Fields } 3652c2d715a1SJ. Bruce Fields 3653c2d715a1SJ. Bruce Fields static __be32 nfsd4_match_existing_connection(struct svc_rqst *rqst, 365402579b2fSDai Ngo struct nfsd4_session *session, u32 req, struct nfsd4_conn **conn) 3655c2d715a1SJ. Bruce Fields { 3656c2d715a1SJ. Bruce Fields struct nfs4_client *clp = session->se_client; 3657c2d715a1SJ. Bruce Fields struct svc_xprt *xpt = rqst->rq_xprt; 3658c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3659c2d715a1SJ. Bruce Fields __be32 status; 3660c2d715a1SJ. Bruce Fields 3661c2d715a1SJ. Bruce Fields /* Following the last paragraph of RFC 5661 Section 18.34.3: */ 3662c2d715a1SJ. Bruce Fields spin_lock(&clp->cl_lock); 3663c2d715a1SJ. Bruce Fields c = __nfsd4_find_conn(xpt, session); 3664c2d715a1SJ. Bruce Fields if (!c) 3665c2d715a1SJ. Bruce Fields status = nfserr_noent; 3666c2d715a1SJ. Bruce Fields else if (req == c->cn_flags) 3667c2d715a1SJ. Bruce Fields status = nfs_ok; 3668c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_FORE_OR_BOTH && 3669c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_BACK) 3670c2d715a1SJ. Bruce Fields status = nfs_ok; 3671c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_BACK_OR_BOTH && 3672c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_FORE) 3673c2d715a1SJ. Bruce Fields status = nfs_ok; 3674c2d715a1SJ. Bruce Fields else 3675c2d715a1SJ. Bruce Fields status = nfserr_inval; 3676c2d715a1SJ. Bruce Fields spin_unlock(&clp->cl_lock); 367702579b2fSDai Ngo if (status == nfs_ok && conn) 367802579b2fSDai Ngo *conn = c; 3679c2d715a1SJ. Bruce Fields return status; 3680c2d715a1SJ. Bruce Fields } 3681c2d715a1SJ. Bruce Fields 36821d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 36831d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 3684eb69853dSChristoph Hellwig union nfsd4_op_u *u) 36851d1bc8f2SJ. Bruce Fields { 3686eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 36871d1bc8f2SJ. Bruce Fields __be32 status; 36883ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 36894f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 3690d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3691d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 36921d1bc8f2SJ. Bruce Fields 36931d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 36941d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 3695c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3696d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 3697c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 36984f6e6c17SJ. Bruce Fields if (!session) 3699d4e19e70STrond Myklebust goto out_no_session; 370057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3701dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 370257266a6eSJ. Bruce Fields goto out; 370302579b2fSDai Ngo status = nfsd4_match_existing_connection(rqstp, session, 370402579b2fSDai Ngo bcts->dir, &conn); 370502579b2fSDai Ngo if (status == nfs_ok) { 370602579b2fSDai Ngo if (bcts->dir == NFS4_CDFC4_FORE_OR_BOTH || 370702579b2fSDai Ngo bcts->dir == NFS4_CDFC4_BACK) 370802579b2fSDai Ngo conn->cn_flags |= NFS4_CDFC4_BACK; 370902579b2fSDai Ngo nfsd4_probe_callback(session->se_client); 371002579b2fSDai Ngo goto out; 371102579b2fSDai Ngo } 371202579b2fSDai Ngo if (status == nfserr_inval) 3713c2d715a1SJ. Bruce Fields goto out; 37141d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 37153ba63671SJ. Bruce Fields if (status) 37164f6e6c17SJ. Bruce Fields goto out; 37173ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 37184f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 37193ba63671SJ. Bruce Fields if (!conn) 37204f6e6c17SJ. Bruce Fields goto out; 37214f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 37224f6e6c17SJ. Bruce Fields status = nfs_ok; 37234f6e6c17SJ. Bruce Fields out: 3724d4e19e70STrond Myklebust nfsd4_put_session(session); 3725d4e19e70STrond Myklebust out_no_session: 37264f6e6c17SJ. Bruce Fields return status; 37271d1bc8f2SJ. Bruce Fields } 37281d1bc8f2SJ. Bruce Fields 3729665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 37305d4cec2fSJ. Bruce Fields { 3731665d5072SJ. Bruce Fields if (!cstate->session) 373251d87bc2SFengguang Wu return false; 3733665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 37345d4cec2fSJ. Bruce Fields } 37355d4cec2fSJ. Bruce Fields 3736069b6ad4SAndy Adamson __be32 3737eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 3738eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3739069b6ad4SAndy Adamson { 3740ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 3741e10e0cfcSBenny Halevy struct nfsd4_session *ses; 3742abcdff09SJ. Bruce Fields __be32 status; 3743f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 3744d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 3745d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3746e10e0cfcSBenny Halevy 3747abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 3748ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 374957716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 3750abcdff09SJ. Bruce Fields goto out; 3751f0f51f5cSJ. Bruce Fields ref_held_by_me++; 375257716355SJ. Bruce Fields } 3753ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 3754c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3755ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 3756abcdff09SJ. Bruce Fields if (!ses) 3757abcdff09SJ. Bruce Fields goto out_client_lock; 375857266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3759dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 3760d4e19e70STrond Myklebust goto out_put_session; 3761f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 376266b2b9b2SJ. Bruce Fields if (status) 3763f0f51f5cSJ. Bruce Fields goto out_put_session; 3764e10e0cfcSBenny Halevy unhash_session(ses); 3765c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3766e10e0cfcSBenny Halevy 376784f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 376819cf5c02SJ. Bruce Fields 3769c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3770e10e0cfcSBenny Halevy status = nfs_ok; 3771f0f51f5cSJ. Bruce Fields out_put_session: 3772d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3773abcdff09SJ. Bruce Fields out_client_lock: 3774abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3775e10e0cfcSBenny Halevy out: 3776e10e0cfcSBenny Halevy return status; 3777069b6ad4SAndy Adamson } 3778069b6ad4SAndy Adamson 377957266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3780328ead28SJ. Bruce Fields { 3781328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3782a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 378357266a6eSJ. Bruce Fields __be32 status = nfs_ok; 378421b75b01SJ. Bruce Fields int ret; 3785328ead28SJ. Bruce Fields 3786328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3787a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 378857266a6eSJ. Bruce Fields if (c) 378957266a6eSJ. Bruce Fields goto out_free; 379057266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 379157266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 379257266a6eSJ. Bruce Fields goto out_free; 3793328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3794328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 379521b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 379621b75b01SJ. Bruce Fields if (ret) 379721b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 379821b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 379957266a6eSJ. Bruce Fields return nfs_ok; 380057266a6eSJ. Bruce Fields out_free: 380157266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 380257266a6eSJ. Bruce Fields free_conn(new); 380357266a6eSJ. Bruce Fields return status; 3804328ead28SJ. Bruce Fields } 3805328ead28SJ. Bruce Fields 3806868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3807868b89c3SMi Jinlong { 3808868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3809868b89c3SMi Jinlong 3810868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3811868b89c3SMi Jinlong } 3812868b89c3SMi Jinlong 3813ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3814ae82a8d0SMi Jinlong struct nfsd4_session *session) 3815ae82a8d0SMi Jinlong { 3816ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3817ae82a8d0SMi Jinlong 3818ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3819ae82a8d0SMi Jinlong } 3820ae82a8d0SMi Jinlong 382153da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 382253da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 382353da6a53SJ. Bruce Fields { 382453da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 382553da6a53SJ. Bruce Fields 382653da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 382753da6a53SJ. Bruce Fields (bool)seq->cachethis) 382853da6a53SJ. Bruce Fields return false; 382953da6a53SJ. Bruce Fields /* 38306e73e92bSScott Mayhew * If there's an error then the reply can have fewer ops than 38316e73e92bSScott Mayhew * the call. 383253da6a53SJ. Bruce Fields */ 38336e73e92bSScott Mayhew if (slot->sl_opcnt < argp->opcnt && !slot->sl_status) 38346e73e92bSScott Mayhew return false; 38356e73e92bSScott Mayhew /* 38366e73e92bSScott Mayhew * But if we cached a reply with *more* ops than the call you're 38376e73e92bSScott Mayhew * sending us now, then this new call is clearly not really a 38386e73e92bSScott Mayhew * replay of the old one: 38396e73e92bSScott Mayhew */ 38406e73e92bSScott Mayhew if (slot->sl_opcnt > argp->opcnt) 384153da6a53SJ. Bruce Fields return false; 384253da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 384353da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 384453da6a53SJ. Bruce Fields return false; 384553da6a53SJ. Bruce Fields /* 384653da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 384753da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 384853da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 384953da6a53SJ. Bruce Fields * the reply), so we don't bother. 385053da6a53SJ. Bruce Fields */ 385153da6a53SJ. Bruce Fields return true; 385253da6a53SJ. Bruce Fields } 385353da6a53SJ. Bruce Fields 3854069b6ad4SAndy Adamson __be32 3855eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3856eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3857069b6ad4SAndy Adamson { 3858eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3859f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 3860bddfdbcdSChuck Lever struct xdr_stream *xdr = resp->xdr; 3861b85d4c01SBenny Halevy struct nfsd4_session *session; 3862221a6876SJ. Bruce Fields struct nfs4_client *clp; 3863b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3864a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 386557b7b43bSJ. Bruce Fields __be32 status; 386647ee5298SJ. Bruce Fields int buflen; 3867d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3868d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3869b85d4c01SBenny Halevy 3870f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3871f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3872f9bb94c4SAndy Adamson 3873a663bdd8SJ. Bruce Fields /* 3874a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3875a663bdd8SJ. Bruce Fields * below. 3876a663bdd8SJ. Bruce Fields */ 3877a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3878a663bdd8SJ. Bruce Fields if (!conn) 3879a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3880a663bdd8SJ. Bruce Fields 3881c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3882d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3883b85d4c01SBenny Halevy if (!session) 3884221a6876SJ. Bruce Fields goto out_no_session; 3885221a6876SJ. Bruce Fields clp = session->se_client; 3886b85d4c01SBenny Halevy 3887868b89c3SMi Jinlong status = nfserr_too_many_ops; 3888868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 388966b2b9b2SJ. Bruce Fields goto out_put_session; 3890868b89c3SMi Jinlong 3891ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3892ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 389366b2b9b2SJ. Bruce Fields goto out_put_session; 3894ae82a8d0SMi Jinlong 3895b85d4c01SBenny Halevy status = nfserr_badslot; 38966c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 389766b2b9b2SJ. Bruce Fields goto out_put_session; 3898b85d4c01SBenny Halevy 3899557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3900b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3901b85d4c01SBenny Halevy 3902a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3903a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3904a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3905a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 3906a8dfdaebSAndy Adamson 390773e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 390873e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 3909b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 3910bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 3911bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 391266b2b9b2SJ. Bruce Fields goto out_put_session; 391353da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 391453da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 391553da6a53SJ. Bruce Fields goto out_put_session; 3916b85d4c01SBenny Halevy cstate->slot = slot; 3917b85d4c01SBenny Halevy cstate->session = session; 39184b24ca7dSJeff Layton cstate->clp = clp; 3919da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 3920557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 3921bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 3922da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 3923aaf84eb9SBenny Halevy goto out; 3924b85d4c01SBenny Halevy } 3925b85d4c01SBenny Halevy if (status) 392666b2b9b2SJ. Bruce Fields goto out_put_session; 3927b85d4c01SBenny Halevy 392857266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 3929a663bdd8SJ. Bruce Fields conn = NULL; 393057266a6eSJ. Bruce Fields if (status) 393157266a6eSJ. Bruce Fields goto out_put_session; 3932328ead28SJ. Bruce Fields 393347ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 393447ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 393547ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 393647ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 393747ee5298SJ. Bruce Fields nfserr_rep_too_big; 3938a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 393947ee5298SJ. Bruce Fields goto out_put_session; 394032aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 394147ee5298SJ. Bruce Fields 394247ee5298SJ. Bruce Fields status = nfs_ok; 3943b85d4c01SBenny Halevy /* Success! bump slot seqid */ 3944b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 3945bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 394673e79482SJ. Bruce Fields if (seq->cachethis) 394773e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 3948bf5c43c8SJ. Bruce Fields else 3949bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 3950b85d4c01SBenny Halevy 3951b85d4c01SBenny Halevy cstate->slot = slot; 3952b85d4c01SBenny Halevy cstate->session = session; 39534b24ca7dSJeff Layton cstate->clp = clp; 3954b85d4c01SBenny Halevy 3955b85d4c01SBenny Halevy out: 39565423732aSBenny Halevy switch (clp->cl_cb_state) { 39575423732aSBenny Halevy case NFSD4_CB_DOWN: 3958fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 39595423732aSBenny Halevy break; 39605423732aSBenny Halevy case NFSD4_CB_FAULT: 3961fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 39625423732aSBenny Halevy break; 3963fc0c3dd1SBenny Halevy default: 3964fc0c3dd1SBenny Halevy seq->status_flags = 0; 39655423732aSBenny Halevy } 39663bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 39673bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 3968221a6876SJ. Bruce Fields out_no_session: 39693f42d2c4SKinglong Mee if (conn) 39703f42d2c4SKinglong Mee free_conn(conn); 3971c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3972b85d4c01SBenny Halevy return status; 397366b2b9b2SJ. Bruce Fields out_put_session: 3974d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 3975221a6876SJ. Bruce Fields goto out_no_session; 3976069b6ad4SAndy Adamson } 3977069b6ad4SAndy Adamson 3978b607664eSTrond Myklebust void 3979b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 3980b607664eSTrond Myklebust { 3981b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 3982b607664eSTrond Myklebust 3983b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 3984b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 3985b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 3986b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 3987b607664eSTrond Myklebust } 3988d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 3989b607664eSTrond Myklebust nfsd4_put_session(cs->session); 39904b24ca7dSJeff Layton } else if (cs->clp) 39914b24ca7dSJeff Layton put_client_renew(cs->clp); 3992b607664eSTrond Myklebust } 3993b607664eSTrond Myklebust 3994345c2842SMi Jinlong __be32 3995eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 3996eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3997eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3998345c2842SMi Jinlong { 3999eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 40006b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 40016b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 400257b7b43bSJ. Bruce Fields __be32 status = 0; 40038daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 4004345c2842SMi Jinlong 40056b10ad19STrond Myklebust spin_lock(&nn->client_lock); 40060a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 40078daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 400878389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 4009345c2842SMi Jinlong 4010345c2842SMi Jinlong if (conf) { 4011c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 4012345c2842SMi Jinlong status = nfserr_clientid_busy; 4013345c2842SMi Jinlong goto out; 4014345c2842SMi Jinlong } 4015fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 4016fd699b8aSJeff Layton if (status) 4017fd699b8aSJeff Layton goto out; 40186b10ad19STrond Myklebust clp = conf; 4019345c2842SMi Jinlong } else if (unconf) 4020345c2842SMi Jinlong clp = unconf; 4021345c2842SMi Jinlong else { 4022345c2842SMi Jinlong status = nfserr_stale_clientid; 4023345c2842SMi Jinlong goto out; 4024345c2842SMi Jinlong } 4025dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 40266b10ad19STrond Myklebust clp = NULL; 402757266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 402857266a6eSJ. Bruce Fields goto out; 402957266a6eSJ. Bruce Fields } 4030c41a9b7aSChuck Lever trace_nfsd_clid_destroyed(&clp->cl_clientid); 40316b10ad19STrond Myklebust unhash_client_locked(clp); 4032345c2842SMi Jinlong out: 40336b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 40346b10ad19STrond Myklebust if (clp) 40356b10ad19STrond Myklebust expire_client(clp); 4036345c2842SMi Jinlong return status; 4037345c2842SMi Jinlong } 4038345c2842SMi Jinlong 4039069b6ad4SAndy Adamson __be32 4040eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 4041eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 40424dc6ec00SJ. Bruce Fields { 4043eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 4044ec59659bSJ. Bruce Fields struct nfs4_client *clp = cstate->clp; 404557b7b43bSJ. Bruce Fields __be32 status = 0; 4046bcecf1ccSMi Jinlong 40474dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 40484dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 40494dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 40504dc6ec00SJ. Bruce Fields /* 40514dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 40524dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 40534dc6ec00SJ. Bruce Fields */ 40544dc6ec00SJ. Bruce Fields return nfs_ok; 40554dc6ec00SJ. Bruce Fields } 4056bcecf1ccSMi Jinlong 4057bcecf1ccSMi Jinlong status = nfserr_complete_already; 4058ec59659bSJ. Bruce Fields if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) 4059bcecf1ccSMi Jinlong goto out; 4060bcecf1ccSMi Jinlong 4061bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 4062ec59659bSJ. Bruce Fields if (is_client_expired(clp)) 40634dc6ec00SJ. Bruce Fields /* 40644dc6ec00SJ. Bruce Fields * The following error isn't really legal. 40654dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 40664dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 40674dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 40684dc6ec00SJ. Bruce Fields * client. 40694dc6ec00SJ. Bruce Fields */ 4070bcecf1ccSMi Jinlong goto out; 4071bcecf1ccSMi Jinlong 4072bcecf1ccSMi Jinlong status = nfs_ok; 4073cee8aa07SChuck Lever trace_nfsd_clid_reclaim_complete(&clp->cl_clientid); 4074ec59659bSJ. Bruce Fields nfsd4_client_record_create(clp); 4075ec59659bSJ. Bruce Fields inc_reclaim_complete(clp); 4076bcecf1ccSMi Jinlong out: 4077bcecf1ccSMi Jinlong return status; 40784dc6ec00SJ. Bruce Fields } 40794dc6ec00SJ. Bruce Fields 40804dc6ec00SJ. Bruce Fields __be32 4081b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4082eb69853dSChristoph Hellwig union nfsd4_op_u *u) 40831da177e4SLinus Torvalds { 4084eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 4085a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 40861da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 40873dbacee6STrond Myklebust struct nfs4_client *conf, *new; 40883dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 4089b37ad28bSAl Viro __be32 status; 4090c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 4091a55370a3SNeilBrown 40925cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 40935cc40fd7STrond Myklebust if (new == NULL) 40945cc40fd7STrond Myklebust return nfserr_jukebox; 40953dbacee6STrond Myklebust spin_lock(&nn->client_lock); 4096382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 40972b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 40981da177e4SLinus Torvalds status = nfserr_clid_inuse; 4099e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 4100e203d506SJ. Bruce Fields goto out; 4101026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 410227787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 41031da177e4SLinus Torvalds goto out; 41041da177e4SLinus Torvalds } 41051da177e4SLinus Torvalds } 4106a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 41071da177e4SLinus Torvalds if (unconf) 41083dbacee6STrond Myklebust unhash_client_locked(unconf); 4109744ea54cSChuck Lever if (conf) { 4110744ea54cSChuck Lever if (same_verf(&conf->cl_verifier, &clverifier)) { 41111da177e4SLinus Torvalds copy_clid(new, conf); 411241eb1670SKinglong Mee gen_confirm(new, nn); 4113744ea54cSChuck Lever } else 4114744ea54cSChuck Lever trace_nfsd_clid_verf_mismatch(conf, rqstp, 4115744ea54cSChuck Lever &clverifier); 4116237f91c8SChuck Lever } else 4117237f91c8SChuck Lever trace_nfsd_clid_fresh(new); 41188323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 41196f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 4120ac55fdc4SJeff Layton add_to_unconfirmed(new); 41211da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 41221da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 41231da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 41245cc40fd7STrond Myklebust new = NULL; 41251da177e4SLinus Torvalds status = nfs_ok; 41261da177e4SLinus Torvalds out: 41273dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 41285cc40fd7STrond Myklebust if (new) 41295cc40fd7STrond Myklebust free_client(new); 4130237f91c8SChuck Lever if (unconf) { 4131237f91c8SChuck Lever trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); 41323dbacee6STrond Myklebust expire_client(unconf); 4133237f91c8SChuck Lever } 41341da177e4SLinus Torvalds return status; 41351da177e4SLinus Torvalds } 41361da177e4SLinus Torvalds 4137b37ad28bSAl Viro __be32 4138b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 4139b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 4140eb69853dSChristoph Hellwig union nfsd4_op_u *u) 41411da177e4SLinus Torvalds { 4142eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 4143eb69853dSChristoph Hellwig &u->setclientid_confirm; 414421ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 4145d20c11d8SJeff Layton struct nfs4_client *old = NULL; 41461da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 41471da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 4148b37ad28bSAl Viro __be32 status; 41497f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 41501da177e4SLinus Torvalds 41512c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 41521da177e4SLinus Torvalds return nfserr_stale_clientid; 415321ab45a4SNeilBrown 4154d20c11d8SJeff Layton spin_lock(&nn->client_lock); 41558daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 41560a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 4157a186e767SJ. Bruce Fields /* 41588695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 41598695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 4160f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 4161f984a7ceSJ. Bruce Fields * 4162f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 4163a186e767SJ. Bruce Fields */ 4164f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 416527787733SChuck Lever if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { 416627787733SChuck Lever trace_nfsd_clid_cred_mismatch(unconf, rqstp); 41678695b90aSJ. Bruce Fields goto out; 416827787733SChuck Lever } 416927787733SChuck Lever if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 417027787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 41718695b90aSJ. Bruce Fields goto out; 417227787733SChuck Lever } 417390d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 41747d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 417590d700b7SJ. Bruce Fields status = nfs_ok; 4176237f91c8SChuck Lever } else 417790d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 417890d700b7SJ. Bruce Fields goto out; 417990d700b7SJ. Bruce Fields } 418090d700b7SJ. Bruce Fields status = nfs_ok; 4181237f91c8SChuck Lever if (conf) { 4182d20c11d8SJeff Layton old = unconf; 4183d20c11d8SJeff Layton unhash_client_locked(old); 41845a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 4185237f91c8SChuck Lever } else { 4186d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 4187d20c11d8SJeff Layton if (old) { 41882b634821SJ. Bruce Fields status = nfserr_clid_inuse; 41892b634821SJ. Bruce Fields if (client_has_state(old) 41902b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 4191ab451ea9SDai Ngo &old->cl_cred)) { 4192ab451ea9SDai Ngo old = NULL; 41932b634821SJ. Bruce Fields goto out; 4194ab451ea9SDai Ngo } 4195d20c11d8SJeff Layton status = mark_client_expired_locked(old); 41967abea1e8SJeff Layton if (status) { 41977abea1e8SJeff Layton old = NULL; 4198221a6876SJ. Bruce Fields goto out; 4199221a6876SJ. Bruce Fields } 42002958d2eeSChuck Lever trace_nfsd_clid_replaced(&old->cl_clientid); 42017abea1e8SJeff Layton } 42021da177e4SLinus Torvalds move_to_confirmed(unconf); 4203d20c11d8SJeff Layton conf = unconf; 420408e8987cSNeilBrown } 4205d20c11d8SJeff Layton get_client_locked(conf); 4206d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4207934bd07fSJ. Bruce Fields if (conf == unconf) 4208934bd07fSJ. Bruce Fields fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); 4209d20c11d8SJeff Layton nfsd4_probe_callback(conf); 4210d20c11d8SJeff Layton spin_lock(&nn->client_lock); 4211d20c11d8SJeff Layton put_client_renew_locked(conf); 42121da177e4SLinus Torvalds out: 4213d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4214d20c11d8SJeff Layton if (old) 4215d20c11d8SJeff Layton expire_client(old); 42161da177e4SLinus Torvalds return status; 42171da177e4SLinus Torvalds } 42181da177e4SLinus Torvalds 421932513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 42201da177e4SLinus Torvalds { 422132513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 422232513b40SJ. Bruce Fields } 422332513b40SJ. Bruce Fields 422432513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 4225f9b60e22SJ. Bruce Fields static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval, 42265b095e99SJeff Layton struct nfs4_file *fp) 422732513b40SJ. Bruce Fields { 4228950e0118STrond Myklebust lockdep_assert_held(&state_lock); 4229950e0118STrond Myklebust 4230818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 42311d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 42328beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 42338beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 42348287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 4235f9b60e22SJ. Bruce Fields fh_copy_shallow(&fp->fi_fhandle, &fh->fh_handle); 42360c637be8SJeff Layton fp->fi_deleg_file = NULL; 423747f9940cSMeelap Shah fp->fi_had_conflict = false; 4238baeb4ff0SJeff Layton fp->fi_share_deny = 0; 4239f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 4240f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 4241a0ce4837SJ. Bruce Fields fp->fi_aliased = false; 4242a0ce4837SJ. Bruce Fields fp->fi_inode = d_inode(fh->fh_dentry); 42439cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 42449cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 4245c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 42469cf514ccSChristoph Hellwig #endif 42475b095e99SJeff Layton hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); 42481da177e4SLinus Torvalds } 42491da177e4SLinus Torvalds 4250e8ff2a84SJ. Bruce Fields void 4251e60d4398SNeilBrown nfsd4_free_slabs(void) 4252e60d4398SNeilBrown { 42539258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4254abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 4255abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4256abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4257abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4258abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 42599258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 4260e60d4398SNeilBrown } 42611da177e4SLinus Torvalds 426272083396SBryan Schumaker int 42631da177e4SLinus Torvalds nfsd4_init_slabs(void) 42641da177e4SLinus Torvalds { 42659258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 42669258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 42679258a2d5SJeff Layton if (client_slab == NULL) 42689258a2d5SJeff Layton goto out; 4269fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 4270fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 4271fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 42729258a2d5SJeff Layton goto out_free_client_slab; 4273fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 42743c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 4275fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 4276abf1135bSChristoph Hellwig goto out_free_openowner_slab; 4277e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 427820c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 4279e60d4398SNeilBrown if (file_slab == NULL) 4280abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 42815ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 4282dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 42835ac049acSNeilBrown if (stateid_slab == NULL) 4284abf1135bSChristoph Hellwig goto out_free_file_slab; 42855b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 428620c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 42875b2d21c1SNeilBrown if (deleg_slab == NULL) 4288abf1135bSChristoph Hellwig goto out_free_stateid_slab; 42898287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 42908287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 42918287f009SSachin Bhamare if (odstate_slab == NULL) 42928287f009SSachin Bhamare goto out_free_deleg_slab; 4293e60d4398SNeilBrown return 0; 4294abf1135bSChristoph Hellwig 42958287f009SSachin Bhamare out_free_deleg_slab: 42968287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 4297abf1135bSChristoph Hellwig out_free_stateid_slab: 4298abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4299abf1135bSChristoph Hellwig out_free_file_slab: 4300abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4301abf1135bSChristoph Hellwig out_free_lockowner_slab: 4302abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4303abf1135bSChristoph Hellwig out_free_openowner_slab: 4304abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 43059258a2d5SJeff Layton out_free_client_slab: 43069258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4307abf1135bSChristoph Hellwig out: 43081da177e4SLinus Torvalds return -ENOMEM; 43091da177e4SLinus Torvalds } 43101da177e4SLinus Torvalds 4311ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 4312ff194bd9SJ. Bruce Fields { 4313ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 4314ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 4315ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 431658fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 431758fb12e6SJeff Layton } 431858fb12e6SJeff Layton 431958fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 432058fb12e6SJeff Layton struct nfs4_stateowner *so) 432158fb12e6SJeff Layton { 432258fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 432358fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 4324b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 432558fb12e6SJeff Layton } 432658fb12e6SJeff Layton } 432758fb12e6SJeff Layton 432858fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 432958fb12e6SJeff Layton { 433058fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 433158fb12e6SJeff Layton 433258fb12e6SJeff Layton if (so != NULL) { 433358fb12e6SJeff Layton cstate->replay_owner = NULL; 433458fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 433558fb12e6SJeff Layton nfs4_put_stateowner(so); 433658fb12e6SJeff Layton } 4337ff194bd9SJ. Bruce Fields } 4338ff194bd9SJ. Bruce Fields 4339fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 43401da177e4SLinus Torvalds { 43411da177e4SLinus Torvalds struct nfs4_stateowner *sop; 43421da177e4SLinus Torvalds 4343fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 4344ff194bd9SJ. Bruce Fields if (!sop) 4345ff194bd9SJ. Bruce Fields return NULL; 4346ff194bd9SJ. Bruce Fields 43476f4859b8SJ. Bruce Fields xdr_netobj_dup(&sop->so_owner, owner, GFP_KERNEL); 4348ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 4349fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 4350ff194bd9SJ. Bruce Fields return NULL; 4351ff194bd9SJ. Bruce Fields } 4352ff194bd9SJ. Bruce Fields 4353ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 4354ff194bd9SJ. Bruce Fields sop->so_client = clp; 4355ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 43566b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 43571da177e4SLinus Torvalds return sop; 43581da177e4SLinus Torvalds } 4359ff194bd9SJ. Bruce Fields 4360fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 4361ff194bd9SJ. Bruce Fields { 4362d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 43639b531137SStanislav Kinsbursky 4364d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 4365d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 4366fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 43671da177e4SLinus Torvalds } 43681da177e4SLinus Torvalds 43698f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 43708f4b54c5SJeff Layton { 4371d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 43728f4b54c5SJeff Layton } 43738f4b54c5SJeff Layton 43746b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 43756b180f0bSJeff Layton { 43766b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 43776b180f0bSJeff Layton 43786b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 43796b180f0bSJeff Layton } 43806b180f0bSJeff Layton 43816b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 43828f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 43836b180f0bSJeff Layton .so_free = nfs4_free_openowner, 43846b180f0bSJeff Layton }; 43856b180f0bSJeff Layton 43867fc0564eSAndrew Elble static struct nfs4_ol_stateid * 43877fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 43887fc0564eSAndrew Elble { 43897fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 43907fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 43917fc0564eSAndrew Elble 43927fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 43937fc0564eSAndrew Elble 43947fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 43957fc0564eSAndrew Elble /* ignore lock owners */ 43967fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 43977fc0564eSAndrew Elble continue; 439815ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 439915ca08d3STrond Myklebust continue; 440015ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 44017fc0564eSAndrew Elble ret = local; 4402a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 44037fc0564eSAndrew Elble break; 44047fc0564eSAndrew Elble } 44057fc0564eSAndrew Elble } 44067fc0564eSAndrew Elble return ret; 44077fc0564eSAndrew Elble } 44087fc0564eSAndrew Elble 440915ca08d3STrond Myklebust static __be32 441015ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 441115ca08d3STrond Myklebust { 441215ca08d3STrond Myklebust __be32 ret = nfs_ok; 441315ca08d3STrond Myklebust 441415ca08d3STrond Myklebust switch (s->sc_type) { 441515ca08d3STrond Myklebust default: 441615ca08d3STrond Myklebust break; 44174f176417STrond Myklebust case 0: 441815ca08d3STrond Myklebust case NFS4_CLOSED_STID: 441915ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 442015ca08d3STrond Myklebust ret = nfserr_bad_stateid; 442115ca08d3STrond Myklebust break; 442215ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 442315ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 442415ca08d3STrond Myklebust } 442515ca08d3STrond Myklebust return ret; 442615ca08d3STrond Myklebust } 442715ca08d3STrond Myklebust 442815ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 442915ca08d3STrond Myklebust static __be32 443015ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 443115ca08d3STrond Myklebust { 443215ca08d3STrond Myklebust __be32 ret; 443315ca08d3STrond Myklebust 44344f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 443515ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 443615ca08d3STrond Myklebust if (ret != nfs_ok) 443715ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 443815ca08d3STrond Myklebust return ret; 443915ca08d3STrond Myklebust } 444015ca08d3STrond Myklebust 444115ca08d3STrond Myklebust static struct nfs4_ol_stateid * 444215ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 444315ca08d3STrond Myklebust { 444415ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 444515ca08d3STrond Myklebust for (;;) { 444615ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 444715ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 444815ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 444915ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 445015ca08d3STrond Myklebust break; 445115ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 445215ca08d3STrond Myklebust } 445315ca08d3STrond Myklebust return stp; 445415ca08d3STrond Myklebust } 445515ca08d3STrond Myklebust 4456fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 445713d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 4458db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 4459db24b3b4SJeff Layton { 446013d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 44617ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 44621da177e4SLinus Torvalds 4463fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 4464fe0750e5SJ. Bruce Fields if (!oo) 44651da177e4SLinus Torvalds return NULL; 44666b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 4467fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 4468fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 4469d3134b10SJeff Layton oo->oo_flags = 0; 4470db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 4471db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 4472fe0750e5SJ. Bruce Fields oo->oo_time = 0; 447338c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 4474fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 4475d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 4476d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 44777ffb5880STrond Myklebust if (ret == NULL) { 4478fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 44797ffb5880STrond Myklebust ret = oo; 44807ffb5880STrond Myklebust } else 4481d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 4482d50ffdedSKinglong Mee 4483d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 4484c5952338SJeff Layton return ret; 44851da177e4SLinus Torvalds } 44861da177e4SLinus Torvalds 44877fc0564eSAndrew Elble static struct nfs4_ol_stateid * 44888c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 44897fc0564eSAndrew Elble { 44901da177e4SLinus Torvalds 44917fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 44927fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 44938c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 44947fc0564eSAndrew Elble 44958c7245abSOleg Drokin stp = open->op_stp; 44965cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 44975cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 44984f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 44995cc1fb2aSOleg Drokin 450015ca08d3STrond Myklebust retry: 45017fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 45027fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 45037fc0564eSAndrew Elble 45047fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 45057fc0564eSAndrew Elble if (retstp) 45067fc0564eSAndrew Elble goto out_unlock; 45078c7245abSOleg Drokin 45088c7245abSOleg Drokin open->op_stp = NULL; 4509a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 45103abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 45113c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 4512b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 451313cd2184SNeilBrown get_nfs4_file(fp); 451411b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 45151da177e4SLinus Torvalds stp->st_access_bmap = 0; 45161da177e4SLinus Torvalds stp->st_deny_bmap = 0; 45174c4cd222SNeilBrown stp->st_openstp = NULL; 45181c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 45191d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 45207fc0564eSAndrew Elble 45217fc0564eSAndrew Elble out_unlock: 45221d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 45231c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 45245cc1fb2aSOleg Drokin if (retstp) { 452515ca08d3STrond Myklebust /* Handle races with CLOSE */ 452615ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 452715ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 452815ca08d3STrond Myklebust goto retry; 452915ca08d3STrond Myklebust } 45308c7245abSOleg Drokin /* To keep mutex tracking happy */ 45315cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 45328c7245abSOleg Drokin stp = retstp; 45335cc1fb2aSOleg Drokin } 45348c7245abSOleg Drokin return stp; 45351da177e4SLinus Torvalds } 45361da177e4SLinus Torvalds 4537d3134b10SJeff Layton /* 4538d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 4539d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 4540d3134b10SJeff Layton * them before returning however. 4541d3134b10SJeff Layton */ 45421da177e4SLinus Torvalds static void 4543d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 45441da177e4SLinus Torvalds { 4545217526e7SJeff Layton struct nfs4_ol_stateid *last; 4546d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 4547d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 4548d3134b10SJeff Layton nfsd_net_id); 454973758fedSStanislav Kinsbursky 4550fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 45511da177e4SLinus Torvalds 4552b401be22SJeff Layton /* 4553b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 4554b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 4555b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 4556b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 4557b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 4558b401be22SJeff Layton * there should be no danger of the refcount going back up again at 4559b401be22SJeff Layton * this point. 4560b401be22SJeff Layton */ 4561a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 4562b401be22SJeff Layton 4563d3134b10SJeff Layton release_all_access(s); 4564d3134b10SJeff Layton if (s->st_stid.sc_file) { 4565d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 4566d3134b10SJeff Layton s->st_stid.sc_file = NULL; 4567d3134b10SJeff Layton } 4568217526e7SJeff Layton 4569217526e7SJeff Layton spin_lock(&nn->client_lock); 4570217526e7SJeff Layton last = oo->oo_last_closed_stid; 4571d3134b10SJeff Layton oo->oo_last_closed_stid = s; 457273758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 457320b7d86fSArnd Bergmann oo->oo_time = ktime_get_boottime_seconds(); 4574217526e7SJeff Layton spin_unlock(&nn->client_lock); 4575217526e7SJeff Layton if (last) 4576217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 45771da177e4SLinus Torvalds } 45781da177e4SLinus Torvalds 45791da177e4SLinus Torvalds /* search file_hashtbl[] for file */ 45801da177e4SLinus Torvalds static struct nfs4_file * 4581f9b60e22SJ. Bruce Fields find_file_locked(struct svc_fh *fh, unsigned int hashval) 45821da177e4SLinus Torvalds { 45831da177e4SLinus Torvalds struct nfs4_file *fp; 45841da177e4SLinus Torvalds 458536a80491SMadhuparna Bhowmik hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, 458636a80491SMadhuparna Bhowmik lockdep_is_held(&state_lock)) { 4587f9b60e22SJ. Bruce Fields if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) { 4588818a34ebSElena Reshetova if (refcount_inc_not_zero(&fp->fi_ref)) 45891da177e4SLinus Torvalds return fp; 45901da177e4SLinus Torvalds } 459113cd2184SNeilBrown } 45921da177e4SLinus Torvalds return NULL; 45931da177e4SLinus Torvalds } 45941da177e4SLinus Torvalds 4595a0ce4837SJ. Bruce Fields static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh, 4596a0ce4837SJ. Bruce Fields unsigned int hashval) 4597a0ce4837SJ. Bruce Fields { 4598a0ce4837SJ. Bruce Fields struct nfs4_file *fp; 4599a0ce4837SJ. Bruce Fields struct nfs4_file *ret = NULL; 4600a0ce4837SJ. Bruce Fields bool alias_found = false; 4601a0ce4837SJ. Bruce Fields 4602a0ce4837SJ. Bruce Fields spin_lock(&state_lock); 4603a0ce4837SJ. Bruce Fields hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, 4604a0ce4837SJ. Bruce Fields lockdep_is_held(&state_lock)) { 4605a0ce4837SJ. Bruce Fields if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) { 4606a0ce4837SJ. Bruce Fields if (refcount_inc_not_zero(&fp->fi_ref)) 4607a0ce4837SJ. Bruce Fields ret = fp; 4608a0ce4837SJ. Bruce Fields } else if (d_inode(fh->fh_dentry) == fp->fi_inode) 4609a0ce4837SJ. Bruce Fields fp->fi_aliased = alias_found = true; 4610a0ce4837SJ. Bruce Fields } 4611a0ce4837SJ. Bruce Fields if (likely(ret == NULL)) { 4612a0ce4837SJ. Bruce Fields nfsd4_init_file(fh, hashval, new); 4613a0ce4837SJ. Bruce Fields new->fi_aliased = alias_found; 4614a0ce4837SJ. Bruce Fields ret = new; 4615a0ce4837SJ. Bruce Fields } 4616a0ce4837SJ. Bruce Fields spin_unlock(&state_lock); 4617a0ce4837SJ. Bruce Fields return ret; 4618a0ce4837SJ. Bruce Fields } 4619a0ce4837SJ. Bruce Fields 4620f9b60e22SJ. Bruce Fields static struct nfs4_file * find_file(struct svc_fh *fh) 4621950e0118STrond Myklebust { 4622950e0118STrond Myklebust struct nfs4_file *fp; 46235b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 4624950e0118STrond Myklebust 46255b095e99SJeff Layton rcu_read_lock(); 46265b095e99SJeff Layton fp = find_file_locked(fh, hashval); 46275b095e99SJeff Layton rcu_read_unlock(); 4628950e0118STrond Myklebust return fp; 4629950e0118STrond Myklebust } 4630950e0118STrond Myklebust 4631950e0118STrond Myklebust static struct nfs4_file * 4632f9b60e22SJ. Bruce Fields find_or_add_file(struct nfs4_file *new, struct svc_fh *fh) 4633950e0118STrond Myklebust { 4634950e0118STrond Myklebust struct nfs4_file *fp; 46355b095e99SJeff Layton unsigned int hashval = file_hashval(fh); 46365b095e99SJeff Layton 46375b095e99SJeff Layton rcu_read_lock(); 46385b095e99SJeff Layton fp = find_file_locked(fh, hashval); 46395b095e99SJeff Layton rcu_read_unlock(); 46405b095e99SJeff Layton if (fp) 46415b095e99SJeff Layton return fp; 4642950e0118STrond Myklebust 4643a0ce4837SJ. Bruce Fields return insert_file(new, fh, hashval); 4644950e0118STrond Myklebust } 4645950e0118STrond Myklebust 46464f83aa30SJ. Bruce Fields /* 46471da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 46481da177e4SLinus Torvalds * WRITE with all zero or all one stateid 46491da177e4SLinus Torvalds */ 4650b37ad28bSAl Viro static __be32 46511da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 46521da177e4SLinus Torvalds { 46531da177e4SLinus Torvalds struct nfs4_file *fp; 4654baeb4ff0SJeff Layton __be32 ret = nfs_ok; 46551da177e4SLinus Torvalds 4656f9b60e22SJ. Bruce Fields fp = find_file(current_fh); 465713cd2184SNeilBrown if (!fp) 4658baeb4ff0SJeff Layton return ret; 4659baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 46601d31a253STrond Myklebust spin_lock(&fp->fi_lock); 4661baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 4662baeb4ff0SJeff Layton ret = nfserr_locked; 46631d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 466413cd2184SNeilBrown put_nfs4_file(fp); 466513cd2184SNeilBrown return ret; 46661da177e4SLinus Torvalds } 46671da177e4SLinus Torvalds 46680162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 46691da177e4SLinus Torvalds { 46700162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 467111b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 467211b9164aSTrond Myklebust nfsd_net_id); 4673e8c69d17SJ. Bruce Fields 467411b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 4675f54fe962SJeff Layton 467602e1215fSJeff Layton /* 467702e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 4678f54fe962SJeff Layton * already holding inode->i_lock. 4679f54fe962SJeff Layton * 4680dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 4681dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 4682dff1399fSJeff Layton */ 4683f54fe962SJeff Layton spin_lock(&state_lock); 4684548ec080SJ. Bruce Fields if (delegation_hashed(dp) && dp->dl_time == 0) { 468520b7d86fSArnd Bergmann dp->dl_time = ktime_get_boottime_seconds(); 468602e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 468702e1215fSJeff Layton } 468802e1215fSJeff Layton spin_unlock(&state_lock); 4689dff1399fSJeff Layton } 46901da177e4SLinus Torvalds 46910162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 46920162ac2bSChristoph Hellwig struct rpc_task *task) 46930162ac2bSChristoph Hellwig { 46940162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 46950162ac2bSChristoph Hellwig 469612ed22f3SJ. Bruce Fields if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID || 469712ed22f3SJ. Bruce Fields dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4698a457974fSAndrew Elble return 1; 4699a457974fSAndrew Elble 47000162ac2bSChristoph Hellwig switch (task->tk_status) { 47010162ac2bSChristoph Hellwig case 0: 47020162ac2bSChristoph Hellwig return 1; 47031c73b9d2SScott Mayhew case -NFS4ERR_DELAY: 47041c73b9d2SScott Mayhew rpc_delay(task, 2 * HZ); 47051c73b9d2SScott Mayhew return 0; 47060162ac2bSChristoph Hellwig case -EBADHANDLE: 47070162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 47080162ac2bSChristoph Hellwig /* 47090162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 47100162ac2bSChristoph Hellwig * granting delegation. 47110162ac2bSChristoph Hellwig */ 47120162ac2bSChristoph Hellwig if (dp->dl_retries--) { 47130162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 47140162ac2bSChristoph Hellwig return 0; 47150162ac2bSChristoph Hellwig } 4716df561f66SGustavo A. R. Silva fallthrough; 47170162ac2bSChristoph Hellwig default: 47181c73b9d2SScott Mayhew return 1; 47190162ac2bSChristoph Hellwig } 47200162ac2bSChristoph Hellwig } 47210162ac2bSChristoph Hellwig 47220162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 47230162ac2bSChristoph Hellwig { 47240162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 47250162ac2bSChristoph Hellwig 47260162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 47270162ac2bSChristoph Hellwig } 47280162ac2bSChristoph Hellwig 4729c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 47300162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 47310162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 47320162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 47330162ac2bSChristoph Hellwig }; 47340162ac2bSChristoph Hellwig 473502e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 473602e1215fSJeff Layton { 473702e1215fSJeff Layton /* 473802e1215fSJeff Layton * We're assuming the state code never drops its reference 473902e1215fSJeff Layton * without first removing the lease. Since we're in this lease 47404a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 47414a269efbSJ. Bruce Fields * i_lock) we know the server hasn't removed the lease yet, and 47424a269efbSJ. Bruce Fields * we know it's safe to take a reference. 474302e1215fSJeff Layton */ 4744a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 4745f0b5de1bSChristoph Hellwig nfsd4_run_cb(&dp->dl_recall); 47466b57d9c8SJ. Bruce Fields } 47476b57d9c8SJ. Bruce Fields 47481c8c601aSJeff Layton /* Called from break_lease() with i_lock held. */ 47494d01b7f5SJeff Layton static bool 47504d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 47516b57d9c8SJ. Bruce Fields { 47524d01b7f5SJeff Layton bool ret = false; 4753653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 4754653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 475566af2579SDai Ngo struct nfs4_client *clp = dp->dl_stid.sc_client; 475666af2579SDai Ngo struct nfsd_net *nn; 47576b57d9c8SJ. Bruce Fields 475817d76ddfSChuck Lever trace_nfsd_cb_recall(&dp->dl_stid); 4759dd5e3fbcSChuck Lever 476066af2579SDai Ngo dp->dl_recalled = true; 476166af2579SDai Ngo atomic_inc(&clp->cl_delegs_in_recall); 476266af2579SDai Ngo if (try_to_expire_client(clp)) { 476366af2579SDai Ngo nn = net_generic(clp->net, nfsd_net_id); 476466af2579SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 476566af2579SDai Ngo } 476666af2579SDai Ngo 47670272e1fdSJ. Bruce Fields /* 47680272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 4769acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 47706b57d9c8SJ. Bruce Fields * in time: 47710272e1fdSJ. Bruce Fields */ 47720272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 47731da177e4SLinus Torvalds 477402e1215fSJeff Layton spin_lock(&fp->fi_lock); 4775417c6629SJeff Layton fp->fi_had_conflict = true; 47765d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 477702e1215fSJeff Layton spin_unlock(&fp->fi_lock); 47784d01b7f5SJeff Layton return ret; 47791da177e4SLinus Torvalds } 47801da177e4SLinus Torvalds 478150719bf3SChuck Lever /** 478250719bf3SChuck Lever * nfsd_breaker_owns_lease - Check if lease conflict was resolved 478350719bf3SChuck Lever * @fl: Lock state to check 478450719bf3SChuck Lever * 478550719bf3SChuck Lever * Return values: 478650719bf3SChuck Lever * %true: Lease conflict was resolved 478750719bf3SChuck Lever * %false: Lease conflict was not resolved. 478850719bf3SChuck Lever */ 478928df3d15SJ. Bruce Fields static bool nfsd_breaker_owns_lease(struct file_lock *fl) 479028df3d15SJ. Bruce Fields { 479128df3d15SJ. Bruce Fields struct nfs4_delegation *dl = fl->fl_owner; 479228df3d15SJ. Bruce Fields struct svc_rqst *rqst; 479328df3d15SJ. Bruce Fields struct nfs4_client *clp; 479428df3d15SJ. Bruce Fields 479528df3d15SJ. Bruce Fields if (!i_am_nfsd()) 479650719bf3SChuck Lever return false; 479728df3d15SJ. Bruce Fields rqst = kthread_data(current); 479813956160SJ. Bruce Fields /* Note rq_prog == NFS_ACL_PROGRAM is also possible: */ 479913956160SJ. Bruce Fields if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4) 480050719bf3SChuck Lever return false; 480128df3d15SJ. Bruce Fields clp = *(rqst->rq_lease_breaker); 480228df3d15SJ. Bruce Fields return dl->dl_stid.sc_client == clp; 480328df3d15SJ. Bruce Fields } 480428df3d15SJ. Bruce Fields 4805c45198edSJeff Layton static int 48067448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 48077448cc37SJeff Layton struct list_head *dispose) 48081da177e4SLinus Torvalds { 480966af2579SDai Ngo struct nfs4_delegation *dp = (struct nfs4_delegation *)onlist->fl_owner; 481066af2579SDai Ngo struct nfs4_client *clp = dp->dl_stid.sc_client; 481166af2579SDai Ngo 481266af2579SDai Ngo if (arg & F_UNLCK) { 481366af2579SDai Ngo if (dp->dl_recalled) 481466af2579SDai Ngo atomic_dec(&clp->cl_delegs_in_recall); 4815c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 481666af2579SDai Ngo } else 48171da177e4SLinus Torvalds return -EAGAIN; 48181da177e4SLinus Torvalds } 48191da177e4SLinus Torvalds 48207b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 482128df3d15SJ. Bruce Fields .lm_breaker_owns_lease = nfsd_breaker_owns_lease, 48228fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 48238fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 48241da177e4SLinus Torvalds }; 48251da177e4SLinus Torvalds 48267a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 48277a8711c9SJ. Bruce Fields { 48287a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 48297a8711c9SJ. Bruce Fields return nfs_ok; 48307a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 48317a8711c9SJ. Bruce Fields return nfserr_replay_me; 48327a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 48337a8711c9SJ. Bruce Fields return nfs_ok; 48347a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 48357a8711c9SJ. Bruce Fields } 48361da177e4SLinus Torvalds 48377950b531SJ. Bruce Fields static struct nfs4_client *lookup_clientid(clientid_t *clid, bool sessions, 48387950b531SJ. Bruce Fields struct nfsd_net *nn) 48397950b531SJ. Bruce Fields { 48407950b531SJ. Bruce Fields struct nfs4_client *found; 48417950b531SJ. Bruce Fields 48427950b531SJ. Bruce Fields spin_lock(&nn->client_lock); 48437950b531SJ. Bruce Fields found = find_confirmed_client(clid, sessions, nn); 48447950b531SJ. Bruce Fields if (found) 48457950b531SJ. Bruce Fields atomic_inc(&found->cl_rpc_users); 48467950b531SJ. Bruce Fields spin_unlock(&nn->client_lock); 48477950b531SJ. Bruce Fields return found; 48487950b531SJ. Bruce Fields } 48497950b531SJ. Bruce Fields 4850460d2709SJ. Bruce Fields static __be32 set_client(clientid_t *clid, 48514b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 4852f71475baSJ. Bruce Fields struct nfsd_net *nn) 48534b24ca7dSJeff Layton { 48544b24ca7dSJeff Layton if (cstate->clp) { 48557950b531SJ. Bruce Fields if (!same_clid(&cstate->clp->cl_clientid, clid)) 48564b24ca7dSJeff Layton return nfserr_stale_clientid; 48574b24ca7dSJeff Layton return nfs_ok; 48584b24ca7dSJeff Layton } 48594b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 48604b24ca7dSJeff Layton return nfserr_stale_clientid; 48614b24ca7dSJeff Layton /* 4862f71475baSJ. Bruce Fields * We're in the 4.0 case (otherwise the SEQUENCE op would have 4863f71475baSJ. Bruce Fields * set cstate->clp), so session = false: 48644b24ca7dSJeff Layton */ 4865f71475baSJ. Bruce Fields cstate->clp = lookup_clientid(clid, false, nn); 48667950b531SJ. Bruce Fields if (!cstate->clp) 48674b24ca7dSJeff Layton return nfserr_expired; 48684b24ca7dSJeff Layton return nfs_ok; 48694b24ca7dSJeff Layton } 48704b24ca7dSJeff Layton 4871b37ad28bSAl Viro __be32 48726668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 48733320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 48741da177e4SLinus Torvalds { 48751da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 48761da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 48771da177e4SLinus Torvalds unsigned int strhashval; 4878fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 48794cdc951bSJ. Bruce Fields __be32 status; 48801da177e4SLinus Torvalds 488132513b40SJ. Bruce Fields /* 488232513b40SJ. Bruce Fields * In case we need it later, after we've already created the 488332513b40SJ. Bruce Fields * file and don't want to risk a further failure: 488432513b40SJ. Bruce Fields */ 488532513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 488632513b40SJ. Bruce Fields if (open->op_file == NULL) 488732513b40SJ. Bruce Fields return nfserr_jukebox; 48881da177e4SLinus Torvalds 4889f71475baSJ. Bruce Fields status = set_client(clientid, cstate, nn); 489013d6f66bSTrond Myklebust if (status) 489113d6f66bSTrond Myklebust return status; 489213d6f66bSTrond Myklebust clp = cstate->clp; 48932d91e895STrond Myklebust 4894d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 4895d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 48962d91e895STrond Myklebust open->op_openowner = oo; 48972d91e895STrond Myklebust if (!oo) { 4898bcf130f9SJ. Bruce Fields goto new_owner; 48990f442aa2SJ. Bruce Fields } 4900dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 49010f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 4902fe0750e5SJ. Bruce Fields release_openowner(oo); 4903fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 4904bcf130f9SJ. Bruce Fields goto new_owner; 49050f442aa2SJ. Bruce Fields } 49064cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 49074cdc951bSJ. Bruce Fields if (status) 49084cdc951bSJ. Bruce Fields return status; 49094cdc951bSJ. Bruce Fields goto alloc_stateid; 4910bcf130f9SJ. Bruce Fields new_owner: 491113d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 4912fe0750e5SJ. Bruce Fields if (oo == NULL) 49133e772463SJ. Bruce Fields return nfserr_jukebox; 4914fe0750e5SJ. Bruce Fields open->op_openowner = oo; 49154cdc951bSJ. Bruce Fields alloc_stateid: 4916b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 49174cdc951bSJ. Bruce Fields if (!open->op_stp) 49184cdc951bSJ. Bruce Fields return nfserr_jukebox; 49198287f009SSachin Bhamare 49208287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 49218287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 49228287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 49238287f009SSachin Bhamare if (!open->op_odstate) 49248287f009SSachin Bhamare return nfserr_jukebox; 49258287f009SSachin Bhamare } 49268287f009SSachin Bhamare 49270f442aa2SJ. Bruce Fields return nfs_ok; 49281da177e4SLinus Torvalds } 49291da177e4SLinus Torvalds 4930b37ad28bSAl Viro static inline __be32 49314a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 49324a6e43e6SNeilBrown { 49334a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 49344a6e43e6SNeilBrown return nfserr_openmode; 49354a6e43e6SNeilBrown else 49364a6e43e6SNeilBrown return nfs_ok; 49374a6e43e6SNeilBrown } 49384a6e43e6SNeilBrown 4939c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 494024a0111eSJ. Bruce Fields { 494124a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 494224a0111eSJ. Bruce Fields } 494324a0111eSJ. Bruce Fields 494438c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 4945f459e453SJ. Bruce Fields { 4946f459e453SJ. Bruce Fields struct nfs4_stid *ret; 4947f459e453SJ. Bruce Fields 494895da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 494995da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 4950f459e453SJ. Bruce Fields if (!ret) 4951f459e453SJ. Bruce Fields return NULL; 4952f459e453SJ. Bruce Fields return delegstateid(ret); 4953f459e453SJ. Bruce Fields } 4954f459e453SJ. Bruce Fields 49558b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 49568b289b2cSJ. Bruce Fields { 49578b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 49588b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 49598b289b2cSJ. Bruce Fields } 49608b289b2cSJ. Bruce Fields 4961b37ad28bSAl Viro static __be32 496241d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 4963567d9829SNeilBrown struct nfs4_delegation **dp) 4964567d9829SNeilBrown { 4965567d9829SNeilBrown int flags; 4966b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 4967dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 4968567d9829SNeilBrown 4969dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 4970dcd94cc2STrond Myklebust if (deleg == NULL) 4971c44c5eebSNeilBrown goto out; 497295da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 497395da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 497495da1b3aSAndrew Elble if (cl->cl_minorversion) 497595da1b3aSAndrew Elble status = nfserr_deleg_revoked; 497695da1b3aSAndrew Elble goto out; 497795da1b3aSAndrew Elble } 497824a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 4979dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 4980dcd94cc2STrond Myklebust if (status) { 4981dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 4982dcd94cc2STrond Myklebust goto out; 4983dcd94cc2STrond Myklebust } 4984dcd94cc2STrond Myklebust *dp = deleg; 4985c44c5eebSNeilBrown out: 49868b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 4987c44c5eebSNeilBrown return nfs_ok; 4988c44c5eebSNeilBrown if (status) 4989c44c5eebSNeilBrown return status; 4990dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 4991c44c5eebSNeilBrown return nfs_ok; 4992567d9829SNeilBrown } 4993567d9829SNeilBrown 499421fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 499521fb4016SJ. Bruce Fields { 499621fb4016SJ. Bruce Fields int flags = 0; 499721fb4016SJ. Bruce Fields 499821fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 499921fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 500021fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 500121fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 500221fb4016SJ. Bruce Fields return flags; 500321fb4016SJ. Bruce Fields } 500421fb4016SJ. Bruce Fields 5005b37ad28bSAl Viro static inline __be32 50061da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 50071da177e4SLinus Torvalds struct nfsd4_open *open) 50081da177e4SLinus Torvalds { 50091da177e4SLinus Torvalds struct iattr iattr = { 50101da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 50111da177e4SLinus Torvalds .ia_size = 0, 50121da177e4SLinus Torvalds }; 50131da177e4SLinus Torvalds if (!open->op_truncate) 50141da177e4SLinus Torvalds return 0; 50151da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 50169246585aSAl Viro return nfserr_inval; 50172a1aa489SArnd Bergmann return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0); 50181da177e4SLinus Torvalds } 50191da177e4SLinus Torvalds 50207e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 50216eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 5022*3d694271SDai Ngo struct nfsd4_open *open, bool new_stp) 50237e6a72e5SChristoph Hellwig { 5024fd4f83fdSJeff Layton struct nfsd_file *nf = NULL; 50257e6a72e5SChristoph Hellwig __be32 status; 50267e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 50277e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 5028baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 50297e6a72e5SChristoph Hellwig 5030de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 5031baeb4ff0SJeff Layton 5032baeb4ff0SJeff Layton /* 5033baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 5034baeb4ff0SJeff Layton * current access? 5035baeb4ff0SJeff Layton */ 5036baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 5037baeb4ff0SJeff Layton if (status != nfs_ok) { 5038*3d694271SDai Ngo if (status != nfserr_share_denied) { 5039*3d694271SDai Ngo spin_unlock(&fp->fi_lock); 5040*3d694271SDai Ngo goto out; 5041*3d694271SDai Ngo } 5042*3d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, 5043*3d694271SDai Ngo stp, open->op_share_deny, false)) 5044*3d694271SDai Ngo status = nfserr_jukebox; 5045baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 5046baeb4ff0SJeff Layton goto out; 5047baeb4ff0SJeff Layton } 5048baeb4ff0SJeff Layton 5049baeb4ff0SJeff Layton /* set access to the file */ 5050baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 5051baeb4ff0SJeff Layton if (status != nfs_ok) { 5052*3d694271SDai Ngo if (status != nfserr_share_denied) { 5053*3d694271SDai Ngo spin_unlock(&fp->fi_lock); 5054*3d694271SDai Ngo goto out; 5055*3d694271SDai Ngo } 5056*3d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, 5057*3d694271SDai Ngo stp, open->op_share_access, true)) 5058*3d694271SDai Ngo status = nfserr_jukebox; 5059baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 5060baeb4ff0SJeff Layton goto out; 5061baeb4ff0SJeff Layton } 5062baeb4ff0SJeff Layton 5063baeb4ff0SJeff Layton /* Set access bits in stateid */ 5064baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 5065baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 5066baeb4ff0SJeff Layton 5067baeb4ff0SJeff Layton /* Set new deny mask */ 5068baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 5069baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 5070baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 5071baeb4ff0SJeff Layton 50727e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 5073de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 5074fd4f83fdSJeff Layton status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); 50757e6a72e5SChristoph Hellwig if (status) 5076baeb4ff0SJeff Layton goto out_put_access; 5077de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 5078de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 5079fd4f83fdSJeff Layton fp->fi_fds[oflag] = nf; 5080fd4f83fdSJeff Layton nf = NULL; 5081de18643dSTrond Myklebust } 50827e6a72e5SChristoph Hellwig } 5083de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 5084fd4f83fdSJeff Layton if (nf) 5085fd4f83fdSJeff Layton nfsd_file_put(nf); 50867e6a72e5SChristoph Hellwig 5087217fd6f6SJ. Bruce Fields status = nfserrno(nfsd_open_break_lease(cur_fh->fh_dentry->d_inode, 5088217fd6f6SJ. Bruce Fields access)); 5089217fd6f6SJ. Bruce Fields if (status) 5090217fd6f6SJ. Bruce Fields goto out_put_access; 5091217fd6f6SJ. Bruce Fields 50927e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 50937e6a72e5SChristoph Hellwig if (status) 50947e6a72e5SChristoph Hellwig goto out_put_access; 50957e6a72e5SChristoph Hellwig out: 50967e6a72e5SChristoph Hellwig return status; 5097baeb4ff0SJeff Layton out_put_access: 5098baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 5099baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 5100baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 5101baeb4ff0SJeff Layton goto out; 51027e6a72e5SChristoph Hellwig } 51037e6a72e5SChristoph Hellwig 5104b37ad28bSAl Viro static __be32 5105*3d694271SDai Ngo nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, 5106*3d694271SDai Ngo struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 5107*3d694271SDai Ngo struct nfsd4_open *open) 51081da177e4SLinus Torvalds { 5109b37ad28bSAl Viro __be32 status; 51106ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 51111da177e4SLinus Torvalds 51126eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 5113*3d694271SDai Ngo return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false); 51147e6a72e5SChristoph Hellwig 5115baeb4ff0SJeff Layton /* test and set deny mode */ 5116baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 5117baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 5118baeb4ff0SJeff Layton if (status == nfs_ok) { 5119*3d694271SDai Ngo if (status != nfserr_share_denied) { 5120baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 5121baeb4ff0SJeff Layton fp->fi_share_deny |= 5122baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 5123*3d694271SDai Ngo } else { 5124*3d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, false, 5125*3d694271SDai Ngo stp, open->op_share_deny, false)) 5126*3d694271SDai Ngo status = nfserr_jukebox; 5127*3d694271SDai Ngo } 51281da177e4SLinus Torvalds } 5129baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 51301da177e4SLinus Torvalds 5131baeb4ff0SJeff Layton if (status != nfs_ok) 5132baeb4ff0SJeff Layton return status; 5133baeb4ff0SJeff Layton 5134baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 5135baeb4ff0SJeff Layton if (status != nfs_ok) 5136baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 5137baeb4ff0SJeff Layton return status; 5138baeb4ff0SJeff Layton } 51391da177e4SLinus Torvalds 514014a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 514114a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 514214a24e99SJ. Bruce Fields { 514314a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 514414a24e99SJ. Bruce Fields return true; 514514a24e99SJ. Bruce Fields /* 514614a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 514714a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 514814a24e99SJ. Bruce Fields * until we hear otherwise: 514914a24e99SJ. Bruce Fields */ 515014a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 515114a24e99SJ. Bruce Fields } 515214a24e99SJ. Bruce Fields 5153653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 5154653e514eSJ. Bruce Fields int flag) 515522d38c4cSJ. Bruce Fields { 515622d38c4cSJ. Bruce Fields struct file_lock *fl; 515722d38c4cSJ. Bruce Fields 515822d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 515922d38c4cSJ. Bruce Fields if (!fl) 516022d38c4cSJ. Bruce Fields return NULL; 516122d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 5162617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 516322d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 516422d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 5165653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 516622d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 5167eb82dd39SJeff Layton fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; 516822d38c4cSJ. Bruce Fields return fl; 516922d38c4cSJ. Bruce Fields } 517022d38c4cSJ. Bruce Fields 5171aba2072fSJ. Bruce Fields static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, 5172aba2072fSJ. Bruce Fields struct nfs4_file *fp) 5173aba2072fSJ. Bruce Fields { 5174aba2072fSJ. Bruce Fields struct nfs4_ol_stateid *st; 5175aba2072fSJ. Bruce Fields struct file *f = fp->fi_deleg_file->nf_file; 5176aba2072fSJ. Bruce Fields struct inode *ino = locks_inode(f); 5177aba2072fSJ. Bruce Fields int writes; 5178aba2072fSJ. Bruce Fields 5179aba2072fSJ. Bruce Fields writes = atomic_read(&ino->i_writecount); 5180aba2072fSJ. Bruce Fields if (!writes) 5181aba2072fSJ. Bruce Fields return 0; 5182aba2072fSJ. Bruce Fields /* 5183aba2072fSJ. Bruce Fields * There could be multiple filehandles (hence multiple 5184aba2072fSJ. Bruce Fields * nfs4_files) referencing this file, but that's not too 5185aba2072fSJ. Bruce Fields * common; let's just give up in that case rather than 5186aba2072fSJ. Bruce Fields * trying to go look up all the clients using that other 5187aba2072fSJ. Bruce Fields * nfs4_file as well: 5188aba2072fSJ. Bruce Fields */ 5189aba2072fSJ. Bruce Fields if (fp->fi_aliased) 5190aba2072fSJ. Bruce Fields return -EAGAIN; 5191aba2072fSJ. Bruce Fields /* 5192aba2072fSJ. Bruce Fields * If there's a close in progress, make sure that we see it 5193aba2072fSJ. Bruce Fields * clear any fi_fds[] entries before we see it decrement 5194aba2072fSJ. Bruce Fields * i_writecount: 5195aba2072fSJ. Bruce Fields */ 5196aba2072fSJ. Bruce Fields smp_mb__after_atomic(); 5197aba2072fSJ. Bruce Fields 5198aba2072fSJ. Bruce Fields if (fp->fi_fds[O_WRONLY]) 5199aba2072fSJ. Bruce Fields writes--; 5200aba2072fSJ. Bruce Fields if (fp->fi_fds[O_RDWR]) 5201aba2072fSJ. Bruce Fields writes--; 5202aba2072fSJ. Bruce Fields if (writes > 0) 5203aba2072fSJ. Bruce Fields return -EAGAIN; /* There may be non-NFSv4 writers */ 5204aba2072fSJ. Bruce Fields /* 5205aba2072fSJ. Bruce Fields * It's possible there are non-NFSv4 write opens in progress, 5206aba2072fSJ. Bruce Fields * but if they haven't incremented i_writecount yet then they 5207aba2072fSJ. Bruce Fields * also haven't called break lease yet; so, they'll break this 5208aba2072fSJ. Bruce Fields * lease soon enough. So, all that's left to check for is NFSv4 5209aba2072fSJ. Bruce Fields * opens: 5210aba2072fSJ. Bruce Fields */ 5211aba2072fSJ. Bruce Fields spin_lock(&fp->fi_lock); 5212aba2072fSJ. Bruce Fields list_for_each_entry(st, &fp->fi_stateids, st_perfile) { 5213aba2072fSJ. Bruce Fields if (st->st_openstp == NULL /* it's an open */ && 5214aba2072fSJ. Bruce Fields access_permit_write(st) && 5215aba2072fSJ. Bruce Fields st->st_stid.sc_client != clp) { 5216aba2072fSJ. Bruce Fields spin_unlock(&fp->fi_lock); 5217aba2072fSJ. Bruce Fields return -EAGAIN; 5218aba2072fSJ. Bruce Fields } 5219aba2072fSJ. Bruce Fields } 5220aba2072fSJ. Bruce Fields spin_unlock(&fp->fi_lock); 5221aba2072fSJ. Bruce Fields /* 5222aba2072fSJ. Bruce Fields * There's a small chance that we could be racing with another 5223aba2072fSJ. Bruce Fields * NFSv4 open. However, any open that hasn't added itself to 5224aba2072fSJ. Bruce Fields * the fi_stateids list also hasn't called break_lease yet; so, 5225aba2072fSJ. Bruce Fields * they'll break this lease soon enough. 5226aba2072fSJ. Bruce Fields */ 5227aba2072fSJ. Bruce Fields return 0; 5228aba2072fSJ. Bruce Fields } 5229aba2072fSJ. Bruce Fields 52300b26693cSJeff Layton static struct nfs4_delegation * 52310b26693cSJeff Layton nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, 52328287f009SSachin Bhamare struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) 5233acfdf5c3SJ. Bruce Fields { 523468b18f52SJ. Bruce Fields int status = 0; 52350b26693cSJeff Layton struct nfs4_delegation *dp; 5236eb82dd39SJeff Layton struct nfsd_file *nf; 5237353601e7SJ. Bruce Fields struct file_lock *fl; 5238417c6629SJeff Layton 5239353601e7SJ. Bruce Fields /* 5240353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 5241353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 5242353601e7SJ. Bruce Fields * the end: 5243353601e7SJ. Bruce Fields */ 5244bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 52450b26693cSJeff Layton return ERR_PTR(-EAGAIN); 52460b26693cSJeff Layton 5247eb82dd39SJeff Layton nf = find_readable_file(fp); 5248eb82dd39SJeff Layton if (!nf) { 5249aba2072fSJ. Bruce Fields /* 5250aba2072fSJ. Bruce Fields * We probably could attempt another open and get a read 5251aba2072fSJ. Bruce Fields * delegation, but for now, don't bother until the 5252aba2072fSJ. Bruce Fields * client actually sends us one. 5253aba2072fSJ. Bruce Fields */ 5254aba2072fSJ. Bruce Fields return ERR_PTR(-EAGAIN); 5255353601e7SJ. Bruce Fields } 525634ed9872SAndrew Elble spin_lock(&state_lock); 525734ed9872SAndrew Elble spin_lock(&fp->fi_lock); 525868b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 525968b18f52SJ. Bruce Fields status = -EAGAIN; 5260353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 5261eb82dd39SJeff Layton fp->fi_deleg_file = nf; 5262353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 5263353601e7SJ. Bruce Fields * cleared */ 5264353601e7SJ. Bruce Fields fp->fi_delegees = 1; 5265eb82dd39SJeff Layton nf = NULL; 5266353601e7SJ. Bruce Fields } else 5267353601e7SJ. Bruce Fields fp->fi_delegees++; 5268353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 5269353601e7SJ. Bruce Fields spin_unlock(&state_lock); 5270eb82dd39SJeff Layton if (nf) 5271eb82dd39SJeff Layton nfsd_file_put(nf); 5272353601e7SJ. Bruce Fields if (status) 5273353601e7SJ. Bruce Fields return ERR_PTR(status); 5274353601e7SJ. Bruce Fields 5275353601e7SJ. Bruce Fields status = -ENOMEM; 5276353601e7SJ. Bruce Fields dp = alloc_init_deleg(clp, fp, fh, odstate); 5277353601e7SJ. Bruce Fields if (!dp) 5278353601e7SJ. Bruce Fields goto out_delegees; 5279353601e7SJ. Bruce Fields 5280353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 5281353601e7SJ. Bruce Fields if (!fl) 5282bd8d7250SAndrew Elble goto out_clnt_odstate; 5283353601e7SJ. Bruce Fields 5284eb82dd39SJeff Layton status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); 5285353601e7SJ. Bruce Fields if (fl) 5286353601e7SJ. Bruce Fields locks_free_lock(fl); 5287353601e7SJ. Bruce Fields if (status) 5288353601e7SJ. Bruce Fields goto out_clnt_odstate; 5289aba2072fSJ. Bruce Fields status = nfsd4_check_conflicting_opens(clp, fp); 5290aba2072fSJ. Bruce Fields if (status) 5291aba2072fSJ. Bruce Fields goto out_unlock; 5292353601e7SJ. Bruce Fields 5293353601e7SJ. Bruce Fields spin_lock(&state_lock); 5294353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 5295353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 5296353601e7SJ. Bruce Fields status = -EAGAIN; 5297353601e7SJ. Bruce Fields else 5298353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 529934ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 530034ed9872SAndrew Elble spin_unlock(&state_lock); 530134ed9872SAndrew Elble 530234ed9872SAndrew Elble if (status) 5303692ad280SAndrew Elble goto out_unlock; 5304692ad280SAndrew Elble 53050b26693cSJeff Layton return dp; 5306692ad280SAndrew Elble out_unlock: 5307eb82dd39SJeff Layton vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); 5308353601e7SJ. Bruce Fields out_clnt_odstate: 5309353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 5310353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 5311353601e7SJ. Bruce Fields out_delegees: 5312353601e7SJ. Bruce Fields put_deleg_file(fp); 5313353601e7SJ. Bruce Fields return ERR_PTR(status); 5314edab9782SJ. Bruce Fields } 5315edab9782SJ. Bruce Fields 53164aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 53174aa8913cSBenny Halevy { 53184aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 53194aa8913cSBenny Halevy if (status == -EAGAIN) 53204aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 53214aa8913cSBenny Halevy else { 53224aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 53234aa8913cSBenny Halevy switch (open->op_deleg_want) { 53244aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 53254aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 53264aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 53274aa8913cSBenny Halevy break; 53284aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 53294aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 53304aa8913cSBenny Halevy break; 53314aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 5332063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 53334aa8913cSBenny Halevy } 53344aa8913cSBenny Halevy } 53354aa8913cSBenny Halevy } 53364aa8913cSBenny Halevy 53371da177e4SLinus Torvalds /* 53381da177e4SLinus Torvalds * Attempt to hand out a delegation. 533999c41515SJ. Bruce Fields * 534099c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 534199c41515SJ. Bruce Fields * proper support for them. 53421da177e4SLinus Torvalds */ 53431da177e4SLinus Torvalds static void 53444cf59221SJeff Layton nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, 53454cf59221SJeff Layton struct nfs4_ol_stateid *stp) 53461da177e4SLinus Torvalds { 53471da177e4SLinus Torvalds struct nfs4_delegation *dp; 53484cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 53494cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 535014a24e99SJ. Bruce Fields int cb_up; 535199c41515SJ. Bruce Fields int status = 0; 53521da177e4SLinus Torvalds 5353fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 53547b190fecSNeilBrown open->op_recall = 0; 53557b190fecSNeilBrown switch (open->op_claim_type) { 53567b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 53572bf23875SJ. Bruce Fields if (!cb_up) 53587b190fecSNeilBrown open->op_recall = 1; 535999c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 536099c41515SJ. Bruce Fields goto out_no_deleg; 53617b190fecSNeilBrown break; 53627b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 5363ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 536499c41515SJ. Bruce Fields /* 536599c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 5366c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 5367c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 536899c41515SJ. Bruce Fields */ 53694cf59221SJeff Layton if (locks_in_grace(clp->net)) 537099c41515SJ. Bruce Fields goto out_no_deleg; 5371dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 537299c41515SJ. Bruce Fields goto out_no_deleg; 53737b190fecSNeilBrown break; 53747b190fecSNeilBrown default: 537599c41515SJ. Bruce Fields goto out_no_deleg; 53767b190fecSNeilBrown } 53778287f009SSachin Bhamare dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); 53780b26693cSJeff Layton if (IS_ERR(dp)) 5379dd239cc0SJ. Bruce Fields goto out_no_deleg; 53801da177e4SLinus Torvalds 5381d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 53821da177e4SLinus Torvalds 53833caf9175SHou Tao trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); 538499c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 538567cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5386dd239cc0SJ. Bruce Fields return; 5387dd239cc0SJ. Bruce Fields out_no_deleg: 538899c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 53897b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 5390d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 53911da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 5392d08d32e6SJ. Bruce Fields open->op_recall = 1; 5393d08d32e6SJ. Bruce Fields } 5394dd239cc0SJ. Bruce Fields 5395dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 5396dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 5397dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 5398dd239cc0SJ. Bruce Fields return; 53991da177e4SLinus Torvalds } 54001da177e4SLinus Torvalds 5401e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 5402e27f49c3SBenny Halevy struct nfs4_delegation *dp) 5403e27f49c3SBenny Halevy { 5404e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 5405e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5406e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5407e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 5408e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 5409e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5410e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5411e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 5412e27f49c3SBenny Halevy } 5413e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 5414e27f49c3SBenny Halevy * it already has, therefore we don't return 5415e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 5416e27f49c3SBenny Halevy */ 5417e27f49c3SBenny Halevy } 5418e27f49c3SBenny Halevy 5419b37ad28bSAl Viro __be32 54201da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 54211da177e4SLinus Torvalds { 54226668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 542338c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 54241da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 5425dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 5426567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 5427b37ad28bSAl Viro __be32 status; 5428d8a1a000STrond Myklebust bool new_stp = false; 54291da177e4SLinus Torvalds 54301da177e4SLinus Torvalds /* 54311da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 54321da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 54331da177e4SLinus Torvalds * If not found, create the nfs4_file struct 54341da177e4SLinus Torvalds */ 5435f9b60e22SJ. Bruce Fields fp = find_or_add_file(open->op_file, current_fh); 5436950e0118STrond Myklebust if (fp != open->op_file) { 543741d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 5438c44c5eebSNeilBrown if (status) 5439c44c5eebSNeilBrown goto out; 544015ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 54411da177e4SLinus Torvalds } else { 5442950e0118STrond Myklebust open->op_file = NULL; 5443c44c5eebSNeilBrown status = nfserr_bad_stateid; 54448b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 5445c44c5eebSNeilBrown goto out; 54461da177e4SLinus Torvalds } 54471da177e4SLinus Torvalds 5448d8a1a000STrond Myklebust if (!stp) { 5449d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 5450d8a1a000STrond Myklebust if (!open->op_stp) 5451d8a1a000STrond Myklebust new_stp = true; 5452d8a1a000STrond Myklebust } 5453d8a1a000STrond Myklebust 54541da177e4SLinus Torvalds /* 54551da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 54561da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 5457d8a1a000STrond Myklebust * 5458d8a1a000STrond Myklebust * stp is already locked. 54591da177e4SLinus Torvalds */ 5460d8a1a000STrond Myklebust if (!new_stp) { 54611da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 5462f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 546335a92fe8SJeff Layton if (status) { 5464feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 54651da177e4SLinus Torvalds goto out; 546635a92fe8SJeff Layton } 54671da177e4SLinus Torvalds } else { 5468*3d694271SDai Ngo status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true); 54696eb3a1d0SJeff Layton if (status) { 5470d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 54716eb3a1d0SJeff Layton release_open_stateid(stp); 5472d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 54736eb3a1d0SJeff Layton goto out; 54746eb3a1d0SJeff Layton } 54758287f009SSachin Bhamare 54768287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 54778287f009SSachin Bhamare open->op_odstate); 54788287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 54798287f009SSachin Bhamare open->op_odstate = NULL; 54801da177e4SLinus Torvalds } 5481d8a1a000STrond Myklebust 54829767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 5483feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 54841da177e4SLinus Torvalds 5485d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 5486d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 5487d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5488d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 5489d24433cdSBenny Halevy goto nodeleg; 5490d24433cdSBenny Halevy } 5491d24433cdSBenny Halevy } 5492d24433cdSBenny Halevy 54931da177e4SLinus Torvalds /* 54941da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 54951da177e4SLinus Torvalds * OPEN succeeds even if we fail. 54961da177e4SLinus Torvalds */ 54974cf59221SJeff Layton nfs4_open_delegation(current_fh, open, stp); 5498d24433cdSBenny Halevy nodeleg: 54991da177e4SLinus Torvalds status = nfs_ok; 55003caf9175SHou Tao trace_nfsd_open(&stp->st_stid.sc_stateid); 55011da177e4SLinus Torvalds out: 5502d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 5503d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 5504e27f49c3SBenny Halevy open->op_deleg_want) 5505e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 5506d24433cdSBenny Halevy 550713cd2184SNeilBrown if (fp) 550813cd2184SNeilBrown put_nfs4_file(fp); 550937515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 551087186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 55111da177e4SLinus Torvalds /* 55121da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 55131da177e4SLinus Torvalds */ 55141da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 551519e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 551619e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 551719e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 55181da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 551919e4c347SJeff Layton 5520dcd94cc2STrond Myklebust if (dp) 5521dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5522d6f2bc5dSTrond Myklebust if (stp) 5523d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 55241da177e4SLinus Torvalds 55251da177e4SLinus Torvalds return status; 55261da177e4SLinus Torvalds } 55271da177e4SLinus Torvalds 552858fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 552942297899SJeff Layton struct nfsd4_open *open) 5530d29b20cdSJ. Bruce Fields { 5531d29b20cdSJ. Bruce Fields if (open->op_openowner) { 5532d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 5533d29b20cdSJ. Bruce Fields 5534d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 5535d3134b10SJeff Layton nfs4_put_stateowner(so); 5536d29b20cdSJ. Bruce Fields } 553732513b40SJ. Bruce Fields if (open->op_file) 55385b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 55394cdc951bSJ. Bruce Fields if (open->op_stp) 55406011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 55418287f009SSachin Bhamare if (open->op_odstate) 55428287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 5543d29b20cdSJ. Bruce Fields } 5544d29b20cdSJ. Bruce Fields 5545b37ad28bSAl Viro __be32 5546b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5547eb69853dSChristoph Hellwig union nfsd4_op_u *u) 55481da177e4SLinus Torvalds { 5549eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 55501da177e4SLinus Torvalds struct nfs4_client *clp; 5551b37ad28bSAl Viro __be32 status; 55527f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 55531da177e4SLinus Torvalds 5554dd5e3fbcSChuck Lever trace_nfsd_clid_renew(clid); 5555f71475baSJ. Bruce Fields status = set_client(clid, cstate, nn); 55569b2ef62bSJ. Bruce Fields if (status) 5557b4587eb2SJ. Bruce Fields return status; 55584b24ca7dSJeff Layton clp = cstate->clp; 5559ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 556077a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 5561b4587eb2SJ. Bruce Fields return nfserr_cb_path_down; 5562b4587eb2SJ. Bruce Fields return nfs_ok; 55631da177e4SLinus Torvalds } 55641da177e4SLinus Torvalds 55657f5ef2e9SJeff Layton void 556612760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 5567a76b4319SNeilBrown { 556833dcc481SJeff Layton /* do nothing if grace period already ended */ 5569a51c84edSStanislav Kinsbursky if (nn->grace_ended) 557033dcc481SJeff Layton return; 557133dcc481SJeff Layton 5572dd5e3fbcSChuck Lever trace_nfsd_grace_complete(nn); 5573a51c84edSStanislav Kinsbursky nn->grace_ended = true; 557470b28235SJ. Bruce Fields /* 557570b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 557670b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 557770b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 557870b28235SJ. Bruce Fields * 557970b28235SJ. Bruce Fields */ 5580919b8049SJeff Layton nfsd4_record_grace_done(nn); 558170b28235SJ. Bruce Fields /* 558270b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 558370b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 558470b28235SJ. Bruce Fields * of luck on the next boot. 558570b28235SJ. Bruce Fields * 558670b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 558770b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 558870b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 558970b28235SJ. Bruce Fields */ 55905e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 559170b28235SJ. Bruce Fields /* 559270b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 559370b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 559470b28235SJ. Bruce Fields * regular locking can resume. 559570b28235SJ. Bruce Fields */ 5596a76b4319SNeilBrown } 5597a76b4319SNeilBrown 559803f318caSJ. Bruce Fields /* 559903f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 560003f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 560103f318caSJ. Bruce Fields */ 560203f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 560303f318caSJ. Bruce Fields { 560420b7d86fSArnd Bergmann time64_t double_grace_period_end = nn->boot_time + 560520b7d86fSArnd Bergmann 2 * nn->nfsd4_lease; 560603f318caSJ. Bruce Fields 5607362063a5SScott Mayhew if (nn->track_reclaim_completes && 5608362063a5SScott Mayhew atomic_read(&nn->nr_reclaim_complete) == 5609362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) 5610362063a5SScott Mayhew return false; 561103f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 561203f318caSJ. Bruce Fields return false; 561303f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 561403f318caSJ. Bruce Fields /* 561503f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 561603f318caSJ. Bruce Fields * still not done, give up: 561703f318caSJ. Bruce Fields */ 561820b7d86fSArnd Bergmann if (ktime_get_boottime_seconds() > double_grace_period_end) 561903f318caSJ. Bruce Fields return false; 562003f318caSJ. Bruce Fields return true; 562103f318caSJ. Bruce Fields } 562203f318caSJ. Bruce Fields 56237f7e7a40SJ. Bruce Fields struct laundry_time { 56247f7e7a40SJ. Bruce Fields time64_t cutoff; 56257f7e7a40SJ. Bruce Fields time64_t new_timeo; 56267f7e7a40SJ. Bruce Fields }; 56277f7e7a40SJ. Bruce Fields 56287f7e7a40SJ. Bruce Fields static bool state_expired(struct laundry_time *lt, time64_t last_refresh) 56297f7e7a40SJ. Bruce Fields { 56307f7e7a40SJ. Bruce Fields time64_t time_remaining; 56317f7e7a40SJ. Bruce Fields 56327f7e7a40SJ. Bruce Fields if (last_refresh < lt->cutoff) 56337f7e7a40SJ. Bruce Fields return true; 56347f7e7a40SJ. Bruce Fields time_remaining = last_refresh - lt->cutoff; 56357f7e7a40SJ. Bruce Fields lt->new_timeo = min(lt->new_timeo, time_remaining); 56367f7e7a40SJ. Bruce Fields return false; 56377f7e7a40SJ. Bruce Fields } 56387f7e7a40SJ. Bruce Fields 5639f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 5640f4e44b39SDai Ngo void nfsd4_ssc_init_umount_work(struct nfsd_net *nn) 5641f4e44b39SDai Ngo { 5642f4e44b39SDai Ngo spin_lock_init(&nn->nfsd_ssc_lock); 5643f4e44b39SDai Ngo INIT_LIST_HEAD(&nn->nfsd_ssc_mount_list); 5644f4e44b39SDai Ngo init_waitqueue_head(&nn->nfsd_ssc_waitq); 5645f4e44b39SDai Ngo } 5646f4e44b39SDai Ngo EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); 5647f4e44b39SDai Ngo 5648f4e44b39SDai Ngo /* 5649f4e44b39SDai Ngo * This is called when nfsd is being shutdown, after all inter_ssc 5650f4e44b39SDai Ngo * cleanup were done, to destroy the ssc delayed unmount list. 5651f4e44b39SDai Ngo */ 5652f4e44b39SDai Ngo static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) 5653f4e44b39SDai Ngo { 5654f47dc2d3SDai Ngo struct nfsd4_ssc_umount_item *ni = NULL; 5655f4e44b39SDai Ngo struct nfsd4_ssc_umount_item *tmp; 5656f4e44b39SDai Ngo 5657f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5658f4e44b39SDai Ngo list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { 5659f4e44b39SDai Ngo list_del(&ni->nsui_list); 5660f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5661f4e44b39SDai Ngo mntput(ni->nsui_vfsmount); 5662f4e44b39SDai Ngo kfree(ni); 5663f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5664f4e44b39SDai Ngo } 5665f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5666f4e44b39SDai Ngo } 5667f4e44b39SDai Ngo 5668f4e44b39SDai Ngo static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) 5669f4e44b39SDai Ngo { 5670f4e44b39SDai Ngo bool do_wakeup = false; 56718e70bf27SColin Ian King struct nfsd4_ssc_umount_item *ni = NULL; 5672f4e44b39SDai Ngo struct nfsd4_ssc_umount_item *tmp; 5673f4e44b39SDai Ngo 5674f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5675f4e44b39SDai Ngo list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { 5676f4e44b39SDai Ngo if (time_after(jiffies, ni->nsui_expire)) { 5677f4e44b39SDai Ngo if (refcount_read(&ni->nsui_refcnt) > 1) 5678f4e44b39SDai Ngo continue; 5679f4e44b39SDai Ngo 5680f4e44b39SDai Ngo /* mark being unmount */ 5681f4e44b39SDai Ngo ni->nsui_busy = true; 5682f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5683f4e44b39SDai Ngo mntput(ni->nsui_vfsmount); 5684f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5685f4e44b39SDai Ngo 5686f4e44b39SDai Ngo /* waiters need to start from begin of list */ 5687f4e44b39SDai Ngo list_del(&ni->nsui_list); 5688f4e44b39SDai Ngo kfree(ni); 5689f4e44b39SDai Ngo 5690f4e44b39SDai Ngo /* wakeup ssc_connect waiters */ 5691f4e44b39SDai Ngo do_wakeup = true; 5692f4e44b39SDai Ngo continue; 5693f4e44b39SDai Ngo } 5694f4e44b39SDai Ngo break; 5695f4e44b39SDai Ngo } 5696f4e44b39SDai Ngo if (do_wakeup) 5697f4e44b39SDai Ngo wake_up_all(&nn->nfsd_ssc_waitq); 5698f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5699f4e44b39SDai Ngo } 5700f4e44b39SDai Ngo #endif 5701f4e44b39SDai Ngo 5702*3d694271SDai Ngo static bool 5703*3d694271SDai Ngo nfs4_has_any_locks(struct nfs4_client *clp) 5704*3d694271SDai Ngo { 5705*3d694271SDai Ngo int i; 5706*3d694271SDai Ngo struct nfs4_stateowner *so; 5707*3d694271SDai Ngo 5708*3d694271SDai Ngo spin_lock(&clp->cl_lock); 5709*3d694271SDai Ngo for (i = 0; i < OWNER_HASH_SIZE; i++) { 5710*3d694271SDai Ngo list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i], 5711*3d694271SDai Ngo so_strhash) { 5712*3d694271SDai Ngo if (so->so_is_open_owner) 5713*3d694271SDai Ngo continue; 5714*3d694271SDai Ngo spin_unlock(&clp->cl_lock); 5715*3d694271SDai Ngo return true; 5716*3d694271SDai Ngo } 5717*3d694271SDai Ngo } 5718*3d694271SDai Ngo spin_unlock(&clp->cl_lock); 5719*3d694271SDai Ngo return false; 5720*3d694271SDai Ngo } 5721*3d694271SDai Ngo 572266af2579SDai Ngo /* 572366af2579SDai Ngo * place holder for now, no check for lock blockers yet 572466af2579SDai Ngo */ 572566af2579SDai Ngo static bool 572666af2579SDai Ngo nfs4_anylock_blockers(struct nfs4_client *clp) 572766af2579SDai Ngo { 572866af2579SDai Ngo if (atomic_read(&clp->cl_delegs_in_recall) || 5729*3d694271SDai Ngo !list_empty(&clp->async_copies) || 5730*3d694271SDai Ngo nfs4_has_any_locks(clp)) 573166af2579SDai Ngo return true; 573266af2579SDai Ngo return false; 573366af2579SDai Ngo } 573466af2579SDai Ngo 573566af2579SDai Ngo static void 573666af2579SDai Ngo nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, 573766af2579SDai Ngo struct laundry_time *lt) 573866af2579SDai Ngo { 573966af2579SDai Ngo struct list_head *pos, *next; 574066af2579SDai Ngo struct nfs4_client *clp; 574166af2579SDai Ngo 574266af2579SDai Ngo INIT_LIST_HEAD(reaplist); 574366af2579SDai Ngo spin_lock(&nn->client_lock); 574466af2579SDai Ngo list_for_each_safe(pos, next, &nn->client_lru) { 574566af2579SDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 574666af2579SDai Ngo if (clp->cl_state == NFSD4_EXPIRABLE) 574766af2579SDai Ngo goto exp_client; 574866af2579SDai Ngo if (!state_expired(lt, clp->cl_time)) 574966af2579SDai Ngo break; 575066af2579SDai Ngo if (!atomic_read(&clp->cl_rpc_users)) 575166af2579SDai Ngo clp->cl_state = NFSD4_COURTESY; 575266af2579SDai Ngo if (!client_has_state(clp) || 575366af2579SDai Ngo ktime_get_boottime_seconds() >= 575466af2579SDai Ngo (clp->cl_time + NFSD_COURTESY_CLIENT_TIMEOUT)) 575566af2579SDai Ngo goto exp_client; 575666af2579SDai Ngo if (nfs4_anylock_blockers(clp)) { 575766af2579SDai Ngo exp_client: 575866af2579SDai Ngo if (!mark_client_expired_locked(clp)) 575966af2579SDai Ngo list_add(&clp->cl_lru, reaplist); 576066af2579SDai Ngo } 576166af2579SDai Ngo } 576266af2579SDai Ngo spin_unlock(&nn->client_lock); 576366af2579SDai Ngo } 576466af2579SDai Ngo 576520b7d86fSArnd Bergmann static time64_t 576609121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 57671da177e4SLinus Torvalds { 57681da177e4SLinus Torvalds struct nfs4_client *clp; 5769fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 57701da177e4SLinus Torvalds struct nfs4_delegation *dp; 5771217526e7SJeff Layton struct nfs4_ol_stateid *stp; 57727919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 57731da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 57747f7e7a40SJ. Bruce Fields struct laundry_time lt = { 57757f7e7a40SJ. Bruce Fields .cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease, 57767f7e7a40SJ. Bruce Fields .new_timeo = nn->nfsd4_lease 57777f7e7a40SJ. Bruce Fields }; 5778624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 5779624322f1SOlga Kornievskaia copy_stateid_t *cps_t; 5780624322f1SOlga Kornievskaia int i; 57811da177e4SLinus Torvalds 578203f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 57837f7e7a40SJ. Bruce Fields lt.new_timeo = 0; 578403f318caSJ. Bruce Fields goto out; 578503f318caSJ. Bruce Fields } 578612760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 5787624322f1SOlga Kornievskaia 5788624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 5789624322f1SOlga Kornievskaia idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { 5790624322f1SOlga Kornievskaia cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); 5791624322f1SOlga Kornievskaia if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID && 57927f7e7a40SJ. Bruce Fields state_expired(<, cps->cpntf_time)) 5793624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 5794624322f1SOlga Kornievskaia } 5795624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 579666af2579SDai Ngo nfs4_get_client_reaplist(nn, &reaplist, <); 579736acb66bSBenny Halevy list_for_each_safe(pos, next, &reaplist) { 579836acb66bSBenny Halevy clp = list_entry(pos, struct nfs4_client, cl_lru); 5799dd5e3fbcSChuck Lever trace_nfsd_clid_purged(&clp->cl_clientid); 58004864af97STrond Myklebust list_del_init(&clp->cl_lru); 58011da177e4SLinus Torvalds expire_client(clp); 58021da177e4SLinus Torvalds } 5803cdc97505SBenny Halevy spin_lock(&state_lock); 5804e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 58051da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 58067f7e7a40SJ. Bruce Fields if (!state_expired(<, dp->dl_time)) 58071da177e4SLinus Torvalds break; 58083fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 580942690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 58101da177e4SLinus Torvalds } 5811cdc97505SBenny Halevy spin_unlock(&state_lock); 58122d4a532dSJeff Layton while (!list_empty(&reaplist)) { 58132d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 58142d4a532dSJeff Layton dl_recall_lru); 58152d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 58163bd64a5bSJ. Bruce Fields revoke_delegation(dp); 58171da177e4SLinus Torvalds } 5818217526e7SJeff Layton 5819217526e7SJeff Layton spin_lock(&nn->client_lock); 5820217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 5821217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 5822217526e7SJeff Layton oo_close_lru); 58237f7e7a40SJ. Bruce Fields if (!state_expired(<, oo->oo_time)) 58241da177e4SLinus Torvalds break; 5825217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 5826217526e7SJeff Layton stp = oo->oo_last_closed_stid; 5827217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 5828217526e7SJeff Layton spin_unlock(&nn->client_lock); 5829217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 5830217526e7SJeff Layton spin_lock(&nn->client_lock); 58311da177e4SLinus Torvalds } 5832217526e7SJeff Layton spin_unlock(&nn->client_lock); 5833217526e7SJeff Layton 58347919d0a2SJeff Layton /* 58357919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 58367919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 58377919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 58387919d0a2SJeff Layton * under the assumption that the client is no longer interested. 58397919d0a2SJeff Layton * 58407919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 58417919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 58427919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 58437919d0a2SJeff Layton * indefinitely once the lock does become free. 58447919d0a2SJeff Layton */ 58457919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 58460cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 58477919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 58487919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 58497919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 58507f7e7a40SJ. Bruce Fields if (!state_expired(<, nbl->nbl_time)) 58517919d0a2SJeff Layton break; 58527919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 58537919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 58547919d0a2SJeff Layton } 58550cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 58567919d0a2SJeff Layton 58577919d0a2SJeff Layton while (!list_empty(&reaplist)) { 585864ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 58597919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 58607919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 58617919d0a2SJeff Layton free_blocked_lock(nbl); 58627919d0a2SJeff Layton } 5863f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 5864f4e44b39SDai Ngo /* service the server-to-server copy delayed unmount list */ 5865f4e44b39SDai Ngo nfsd4_ssc_expire_umount(nn); 5866f4e44b39SDai Ngo #endif 586703f318caSJ. Bruce Fields out: 58687f7e7a40SJ. Bruce Fields return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 58691da177e4SLinus Torvalds } 58701da177e4SLinus Torvalds 5871a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 5872a254b246SHarvey Harrison 5873a254b246SHarvey Harrison static void 587409121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 58751da177e4SLinus Torvalds { 587620b7d86fSArnd Bergmann time64_t t; 58772e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 587809121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 587909121281SStanislav Kinsbursky laundromat_work); 58801da177e4SLinus Torvalds 588109121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 588209121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 58831da177e4SLinus Torvalds } 58841da177e4SLinus Torvalds 58858fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 5886f8816512SNeilBrown { 58878fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 5888f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 5889f7a4d872SJ. Bruce Fields return nfs_ok; 58901da177e4SLinus Torvalds } 58911da177e4SLinus Torvalds 58921da177e4SLinus Torvalds static 5893dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 58941da177e4SLinus Torvalds { 5895b37ad28bSAl Viro __be32 status = nfserr_openmode; 58961da177e4SLinus Torvalds 589702921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 589802921914SJ. Bruce Fields if (stp->st_openstp) 589902921914SJ. Bruce Fields stp = stp->st_openstp; 590082c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 59011da177e4SLinus Torvalds goto out; 590282c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 59031da177e4SLinus Torvalds goto out; 59041da177e4SLinus Torvalds status = nfs_ok; 59051da177e4SLinus Torvalds out: 59061da177e4SLinus Torvalds return status; 59071da177e4SLinus Torvalds } 59081da177e4SLinus Torvalds 5909b37ad28bSAl Viro static inline __be32 59105ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 59111da177e4SLinus Torvalds { 5912203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 59131da177e4SLinus Torvalds return nfs_ok; 5914c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 591525985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 59161da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 59171da177e4SLinus Torvalds return nfserr_grace; 59181da177e4SLinus Torvalds } else if (flags & WR_STATE) 59191da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 59201da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 59211da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 59221da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 59231da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 59241da177e4SLinus Torvalds } 59251da177e4SLinus Torvalds 592657b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 59270836f587SJ. Bruce Fields { 59286668958fSAndy Adamson /* 59296668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 59306668958fSAndy Adamson * when it is zero. 59316668958fSAndy Adamson */ 593228dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 593381b82965SJ. Bruce Fields return nfs_ok; 593481b82965SJ. Bruce Fields 593581b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 593681b82965SJ. Bruce Fields return nfs_ok; 59376668958fSAndy Adamson 59380836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 593914b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 59400836f587SJ. Bruce Fields return nfserr_bad_stateid; 59410836f587SJ. Bruce Fields /* 594281b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 594381b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 594481b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 594581b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 594681b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 594781b82965SJ. Bruce Fields * but better performance may result in retrying IO that 594881b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 594981b82965SJ. Bruce Fields * reordered in flight: 59500836f587SJ. Bruce Fields */ 59510836f587SJ. Bruce Fields return nfserr_old_stateid; 59520836f587SJ. Bruce Fields } 59530836f587SJ. Bruce Fields 595403da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 595503da3169STrond Myklebust { 595603da3169STrond Myklebust __be32 ret; 595703da3169STrond Myklebust 595803da3169STrond Myklebust spin_lock(&s->sc_lock); 595903da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 596003da3169STrond Myklebust if (ret == nfs_ok) 596103da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 596203da3169STrond Myklebust spin_unlock(&s->sc_lock); 596303da3169STrond Myklebust return ret; 596403da3169STrond Myklebust } 596503da3169STrond Myklebust 5966ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 5967ebe9cb3bSChristoph Hellwig { 5968ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 5969ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 5970ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 5971ebe9cb3bSChristoph Hellwig return nfs_ok; 5972ebe9cb3bSChristoph Hellwig } 5973ebe9cb3bSChristoph Hellwig 59747df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 597517456804SBryan Schumaker { 597697b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 59771af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 597817456804SBryan Schumaker 5979ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 5980ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 59811af71cc8SJeff Layton return status; 5982663e36f0SJ. Bruce Fields if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) 59831af71cc8SJeff Layton return status; 59841af71cc8SJeff Layton spin_lock(&cl->cl_lock); 59851af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 598697b7e3b6SJ. Bruce Fields if (!s) 59871af71cc8SJeff Layton goto out_unlock; 598803da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 598917456804SBryan Schumaker if (status) 59901af71cc8SJeff Layton goto out_unlock; 599123340032SJ. Bruce Fields switch (s->sc_type) { 599223340032SJ. Bruce Fields case NFS4_DELEG_STID: 59931af71cc8SJeff Layton status = nfs_ok; 59941af71cc8SJeff Layton break; 59953bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 59961af71cc8SJeff Layton status = nfserr_deleg_revoked; 59971af71cc8SJeff Layton break; 599823340032SJ. Bruce Fields case NFS4_OPEN_STID: 599923340032SJ. Bruce Fields case NFS4_LOCK_STID: 6000ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 60011af71cc8SJeff Layton break; 600223340032SJ. Bruce Fields default: 600323340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 6004df561f66SGustavo A. R. Silva fallthrough; 600523340032SJ. Bruce Fields case NFS4_CLOSED_STID: 6006b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 60071af71cc8SJeff Layton status = nfserr_bad_stateid; 600823340032SJ. Bruce Fields } 60091af71cc8SJeff Layton out_unlock: 60101af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 60111af71cc8SJeff Layton return status; 601217456804SBryan Schumaker } 601317456804SBryan Schumaker 6014cd61c522SChristoph Hellwig __be32 60152dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 60162dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 60172dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 601838c2f4b1SJ. Bruce Fields { 60190eb6f20aSJ. Bruce Fields __be32 status; 602095da1b3aSAndrew Elble bool return_revoked = false; 602195da1b3aSAndrew Elble 602295da1b3aSAndrew Elble /* 602395da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 602495da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 602595da1b3aSAndrew Elble */ 602695da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 602795da1b3aSAndrew Elble return_revoked = true; 602895da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 602995da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 603038c2f4b1SJ. Bruce Fields 6031ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 6032ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 603338c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 6034f71475baSJ. Bruce Fields status = set_client(&stateid->si_opaque.so_clid, cstate, nn); 6035a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 60364b24ca7dSJeff Layton if (cstate->session) 6037a8a7c677STrond Myklebust return nfserr_bad_stateid; 603838c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 6039a8a7c677STrond Myklebust } 60400eb6f20aSJ. Bruce Fields if (status) 60410eb6f20aSJ. Bruce Fields return status; 60424b24ca7dSJeff Layton *s = find_stateid_by_type(cstate->clp, stateid, typemask); 604338c2f4b1SJ. Bruce Fields if (!*s) 604438c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 604595da1b3aSAndrew Elble if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 604695da1b3aSAndrew Elble nfs4_put_stid(*s); 604795da1b3aSAndrew Elble if (cstate->minorversion) 604895da1b3aSAndrew Elble return nfserr_deleg_revoked; 604995da1b3aSAndrew Elble return nfserr_bad_stateid; 605095da1b3aSAndrew Elble } 605138c2f4b1SJ. Bruce Fields return nfs_ok; 605238c2f4b1SJ. Bruce Fields } 605338c2f4b1SJ. Bruce Fields 6054eb82dd39SJeff Layton static struct nfsd_file * 6055a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 6056a0649b2dSChristoph Hellwig { 6057af90f707SChristoph Hellwig if (!s) 6058af90f707SChristoph Hellwig return NULL; 6059af90f707SChristoph Hellwig 6060a0649b2dSChristoph Hellwig switch (s->sc_type) { 6061a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 6062a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 6063a0649b2dSChristoph Hellwig return NULL; 6064eb82dd39SJeff Layton return nfsd_file_get(s->sc_file->fi_deleg_file); 6065a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 6066a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 6067a0649b2dSChristoph Hellwig if (flags & RD_STATE) 6068a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 6069a0649b2dSChristoph Hellwig else 6070a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 6071a0649b2dSChristoph Hellwig } 6072a0649b2dSChristoph Hellwig 6073a0649b2dSChristoph Hellwig return NULL; 6074a0649b2dSChristoph Hellwig } 6075a0649b2dSChristoph Hellwig 6076a0649b2dSChristoph Hellwig static __be32 6077d8836f77SJ. Bruce Fields nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) 6078a0649b2dSChristoph Hellwig { 6079a0649b2dSChristoph Hellwig __be32 status; 6080a0649b2dSChristoph Hellwig 6081a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 6082a0649b2dSChristoph Hellwig if (status) 6083a0649b2dSChristoph Hellwig return status; 6084a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 6085a0649b2dSChristoph Hellwig } 6086a0649b2dSChristoph Hellwig 6087af90f707SChristoph Hellwig static __be32 6088af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 60895c4583b2SJeff Layton struct nfsd_file **nfp, int flags) 6090af90f707SChristoph Hellwig { 6091af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 6092eb82dd39SJeff Layton struct nfsd_file *nf; 6093af90f707SChristoph Hellwig __be32 status; 6094af90f707SChristoph Hellwig 6095eb82dd39SJeff Layton nf = nfs4_find_file(s, flags); 6096eb82dd39SJeff Layton if (nf) { 6097af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 6098af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 60995c4583b2SJeff Layton if (status) { 61005c4583b2SJeff Layton nfsd_file_put(nf); 6101eb82dd39SJeff Layton goto out; 61025c4583b2SJeff Layton } 6103af90f707SChristoph Hellwig } else { 6104eb82dd39SJeff Layton status = nfsd_file_acquire(rqstp, fhp, acc, &nf); 6105af90f707SChristoph Hellwig if (status) 6106af90f707SChristoph Hellwig return status; 6107af90f707SChristoph Hellwig } 61085c4583b2SJeff Layton *nfp = nf; 6109eb82dd39SJeff Layton out: 6110eb82dd39SJeff Layton return status; 6111af90f707SChristoph Hellwig } 6112624322f1SOlga Kornievskaia static void 6113624322f1SOlga Kornievskaia _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 6114624322f1SOlga Kornievskaia { 6115624322f1SOlga Kornievskaia WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID); 6116624322f1SOlga Kornievskaia if (!refcount_dec_and_test(&cps->cp_stateid.sc_count)) 6117624322f1SOlga Kornievskaia return; 6118624322f1SOlga Kornievskaia list_del(&cps->cp_list); 6119624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 6120624322f1SOlga Kornievskaia cps->cp_stateid.stid.si_opaque.so_id); 6121624322f1SOlga Kornievskaia kfree(cps); 6122624322f1SOlga Kornievskaia } 6123b7342204SOlga Kornievskaia /* 6124b7342204SOlga Kornievskaia * A READ from an inter server to server COPY will have a 6125b7342204SOlga Kornievskaia * copy stateid. Look up the copy notify stateid from the 6126b7342204SOlga Kornievskaia * idr structure and take a reference on it. 6127b7342204SOlga Kornievskaia */ 6128ce0887acSOlga Kornievskaia __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st, 6129ce0887acSOlga Kornievskaia struct nfs4_client *clp, 6130b7342204SOlga Kornievskaia struct nfs4_cpntf_state **cps) 6131b7342204SOlga Kornievskaia { 6132b7342204SOlga Kornievskaia copy_stateid_t *cps_t; 6133b7342204SOlga Kornievskaia struct nfs4_cpntf_state *state = NULL; 6134b7342204SOlga Kornievskaia 6135b7342204SOlga Kornievskaia if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id) 6136b7342204SOlga Kornievskaia return nfserr_bad_stateid; 6137b7342204SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6138b7342204SOlga Kornievskaia cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id); 6139b7342204SOlga Kornievskaia if (cps_t) { 6140b7342204SOlga Kornievskaia state = container_of(cps_t, struct nfs4_cpntf_state, 6141b7342204SOlga Kornievskaia cp_stateid); 61425277a79eSDan Carpenter if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID) { 61435277a79eSDan Carpenter state = NULL; 61445277a79eSDan Carpenter goto unlock; 61455277a79eSDan Carpenter } 6146ce0887acSOlga Kornievskaia if (!clp) 6147b7342204SOlga Kornievskaia refcount_inc(&state->cp_stateid.sc_count); 6148ce0887acSOlga Kornievskaia else 6149ce0887acSOlga Kornievskaia _free_cpntf_state_locked(nn, state); 6150b7342204SOlga Kornievskaia } 61515277a79eSDan Carpenter unlock: 6152b7342204SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 6153b7342204SOlga Kornievskaia if (!state) 6154b7342204SOlga Kornievskaia return nfserr_bad_stateid; 6155ce0887acSOlga Kornievskaia if (!clp && state) 6156b7342204SOlga Kornievskaia *cps = state; 6157b7342204SOlga Kornievskaia return 0; 6158b7342204SOlga Kornievskaia } 6159b7342204SOlga Kornievskaia 6160b7342204SOlga Kornievskaia static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, 6161b7342204SOlga Kornievskaia struct nfs4_stid **stid) 6162b7342204SOlga Kornievskaia { 6163b7342204SOlga Kornievskaia __be32 status; 6164b7342204SOlga Kornievskaia struct nfs4_cpntf_state *cps = NULL; 616547fdb22dSJ. Bruce Fields struct nfs4_client *found; 6166b7342204SOlga Kornievskaia 6167ce0887acSOlga Kornievskaia status = manage_cpntf_state(nn, st, NULL, &cps); 6168b7342204SOlga Kornievskaia if (status) 6169b7342204SOlga Kornievskaia return status; 6170b7342204SOlga Kornievskaia 617120b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 617247fdb22dSJ. Bruce Fields 617347fdb22dSJ. Bruce Fields status = nfserr_expired; 617447fdb22dSJ. Bruce Fields found = lookup_clientid(&cps->cp_p_clid, true, nn); 617547fdb22dSJ. Bruce Fields if (!found) 6176b7342204SOlga Kornievskaia goto out; 617747fdb22dSJ. Bruce Fields 617847fdb22dSJ. Bruce Fields *stid = find_stateid_by_type(found, &cps->cp_p_stateid, 617947fdb22dSJ. Bruce Fields NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID); 618047fdb22dSJ. Bruce Fields if (*stid) 618147fdb22dSJ. Bruce Fields status = nfs_ok; 618247fdb22dSJ. Bruce Fields else 618347fdb22dSJ. Bruce Fields status = nfserr_bad_stateid; 618447fdb22dSJ. Bruce Fields 618547fdb22dSJ. Bruce Fields put_client_renew(found); 6186b7342204SOlga Kornievskaia out: 6187b7342204SOlga Kornievskaia nfs4_put_cpntf_state(nn, cps); 6188b7342204SOlga Kornievskaia return status; 6189b7342204SOlga Kornievskaia } 6190624322f1SOlga Kornievskaia 6191624322f1SOlga Kornievskaia void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 6192624322f1SOlga Kornievskaia { 6193624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6194624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 6195624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 6196624322f1SOlga Kornievskaia } 6197af90f707SChristoph Hellwig 61981da177e4SLinus Torvalds /* 61991da177e4SLinus Torvalds * Checks for stateid operations 62001da177e4SLinus Torvalds */ 6201b37ad28bSAl Viro __be32 6202af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 6203aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 6204624322f1SOlga Kornievskaia stateid_t *stateid, int flags, struct nfsd_file **nfp, 6205624322f1SOlga Kornievskaia struct nfs4_stid **cstid) 62061da177e4SLinus Torvalds { 6207af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 62083320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 6209af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 6210b37ad28bSAl Viro __be32 status; 62111da177e4SLinus Torvalds 62125c4583b2SJeff Layton if (nfp) 62135c4583b2SJeff Layton *nfp = NULL; 62141da177e4SLinus Torvalds 6215af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 6216074b07d9SJ. Bruce Fields if (cstid) 6217074b07d9SJ. Bruce Fields status = nfserr_bad_stateid; 6218074b07d9SJ. Bruce Fields else 6219074b07d9SJ. Bruce Fields status = check_special_stateids(net, fhp, stateid, 6220074b07d9SJ. Bruce Fields flags); 6221af90f707SChristoph Hellwig goto done; 6222af90f707SChristoph Hellwig } 62231da177e4SLinus Torvalds 62242dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 6225db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 62262dd6e458STrond Myklebust &s, nn); 6227b7342204SOlga Kornievskaia if (status == nfserr_bad_stateid) 6228b7342204SOlga Kornievskaia status = find_cpntf_state(nn, stateid, &s); 622938c2f4b1SJ. Bruce Fields if (status) 6230c2d1d6a8STrond Myklebust return status; 623103da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 6232a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 62330c2a498fSJ. Bruce Fields if (status) 62340c2a498fSJ. Bruce Fields goto out; 6235a0649b2dSChristoph Hellwig 6236f7a4d872SJ. Bruce Fields switch (s->sc_type) { 6237f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 6238a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 6239f7a4d872SJ. Bruce Fields break; 6240f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 6241f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 6242d8836f77SJ. Bruce Fields status = nfs4_check_olstateid(openlockstateid(s), flags); 6243f7a4d872SJ. Bruce Fields break; 6244f7a4d872SJ. Bruce Fields default: 624514bcab1aSTrond Myklebust status = nfserr_bad_stateid; 6246a0649b2dSChristoph Hellwig break; 62471da177e4SLinus Torvalds } 62488fcd461dSJeff Layton if (status) 62498fcd461dSJeff Layton goto out; 62508fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 6251a0649b2dSChristoph Hellwig 6252af90f707SChristoph Hellwig done: 62535c4583b2SJeff Layton if (status == nfs_ok && nfp) 62545c4583b2SJeff Layton status = nfs4_check_file(rqstp, fhp, s, nfp, flags); 62551da177e4SLinus Torvalds out: 6256624322f1SOlga Kornievskaia if (s) { 6257624322f1SOlga Kornievskaia if (!status && cstid) 6258624322f1SOlga Kornievskaia *cstid = s; 6259624322f1SOlga Kornievskaia else 6260fd911011STrond Myklebust nfs4_put_stid(s); 6261624322f1SOlga Kornievskaia } 62621da177e4SLinus Torvalds return status; 62631da177e4SLinus Torvalds } 62641da177e4SLinus Torvalds 6265e1ca12dfSBryan Schumaker /* 626617456804SBryan Schumaker * Test if the stateid is valid 626717456804SBryan Schumaker */ 626817456804SBryan Schumaker __be32 626917456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6270eb69853dSChristoph Hellwig union nfsd4_op_u *u) 627117456804SBryan Schumaker { 6272eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 627303cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 6274ec59659bSJ. Bruce Fields struct nfs4_client *cl = cstate->clp; 627503cfb420SBryan Schumaker 627603cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 62777df302f7SChuck Lever stateid->ts_id_status = 62787df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 627903cfb420SBryan Schumaker 628017456804SBryan Schumaker return nfs_ok; 628117456804SBryan Schumaker } 628217456804SBryan Schumaker 628342691398SChuck Lever static __be32 628442691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 628542691398SChuck Lever { 628642691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 628742691398SChuck Lever __be32 ret; 628842691398SChuck Lever 6289659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 6290659aefb6STrond Myklebust if (ret) 6291659aefb6STrond Myklebust goto out_put_stid; 629242691398SChuck Lever 629342691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 629442691398SChuck Lever if (ret) 629542691398SChuck Lever goto out; 629642691398SChuck Lever 629742691398SChuck Lever ret = nfserr_locks_held; 629842691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 629942691398SChuck Lever lockowner(stp->st_stateowner))) 630042691398SChuck Lever goto out; 630142691398SChuck Lever 630242691398SChuck Lever release_lock_stateid(stp); 630342691398SChuck Lever ret = nfs_ok; 630442691398SChuck Lever 630542691398SChuck Lever out: 630642691398SChuck Lever mutex_unlock(&stp->st_mutex); 6307659aefb6STrond Myklebust out_put_stid: 630842691398SChuck Lever nfs4_put_stid(s); 630942691398SChuck Lever return ret; 631042691398SChuck Lever } 631142691398SChuck Lever 6312e1ca12dfSBryan Schumaker __be32 6313e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6314eb69853dSChristoph Hellwig union nfsd4_op_u *u) 6315e1ca12dfSBryan Schumaker { 6316eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 6317e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 63182da1cec7SJ. Bruce Fields struct nfs4_stid *s; 63193bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 6320ec59659bSJ. Bruce Fields struct nfs4_client *cl = cstate->clp; 63212da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 6322e1ca12dfSBryan Schumaker 63231af71cc8SJeff Layton spin_lock(&cl->cl_lock); 63241af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 63252da1cec7SJ. Bruce Fields if (!s) 63261af71cc8SJeff Layton goto out_unlock; 632703da3169STrond Myklebust spin_lock(&s->sc_lock); 63282da1cec7SJ. Bruce Fields switch (s->sc_type) { 63292da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 6330e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 63311af71cc8SJeff Layton break; 63322da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 63331af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 63341af71cc8SJeff Layton if (ret) 63351af71cc8SJeff Layton break; 63361af71cc8SJeff Layton ret = nfserr_locks_held; 63371af71cc8SJeff Layton break; 63382da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 633903da3169STrond Myklebust spin_unlock(&s->sc_lock); 6340a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 63411af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 634242691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 63431af71cc8SJeff Layton goto out; 63443bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 634503da3169STrond Myklebust spin_unlock(&s->sc_lock); 63463bd64a5bSJ. Bruce Fields dp = delegstateid(s); 63472d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 63482d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 63496011695dSTrond Myklebust nfs4_put_stid(s); 63503bd64a5bSJ. Bruce Fields ret = nfs_ok; 63511af71cc8SJeff Layton goto out; 63521af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 6353e1ca12dfSBryan Schumaker } 635403da3169STrond Myklebust spin_unlock(&s->sc_lock); 63551af71cc8SJeff Layton out_unlock: 63561af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 6357e1ca12dfSBryan Schumaker out: 6358e1ca12dfSBryan Schumaker return ret; 6359e1ca12dfSBryan Schumaker } 6360e1ca12dfSBryan Schumaker 63614c4cd222SNeilBrown static inline int 63624c4cd222SNeilBrown setlkflg (int type) 63634c4cd222SNeilBrown { 63644c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 63654c4cd222SNeilBrown RD_STATE : WR_STATE; 63664c4cd222SNeilBrown } 63671da177e4SLinus Torvalds 6368dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 6369c0a5d93eSJ. Bruce Fields { 6370c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 6371c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 6372c0a5d93eSJ. Bruce Fields __be32 status; 6373c0a5d93eSJ. Bruce Fields 6374c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 6375c0a5d93eSJ. Bruce Fields if (status) 6376c0a5d93eSJ. Bruce Fields return status; 63779271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 63789271d7e5STrond Myklebust if (status != nfs_ok) 63799271d7e5STrond Myklebust return status; 6380f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 638135a92fe8SJeff Layton if (status == nfs_ok) 638235a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 638335a92fe8SJeff Layton if (status != nfs_ok) 6384feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6385f7a4d872SJ. Bruce Fields return status; 6386c0a5d93eSJ. Bruce Fields } 6387c0a5d93eSJ. Bruce Fields 63881da177e4SLinus Torvalds /* 63891da177e4SLinus Torvalds * Checks for sequence id mutating operations. 63901da177e4SLinus Torvalds */ 6391b37ad28bSAl Viro static __be32 6392dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 63932288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 63943320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 63953320fef1SStanislav Kinsbursky struct nfsd_net *nn) 63961da177e4SLinus Torvalds { 63970836f587SJ. Bruce Fields __be32 status; 639838c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6399e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 64001da177e4SLinus Torvalds 6401dd5e3fbcSChuck Lever trace_nfsd_preprocess(seqid, stateid); 64021da177e4SLinus Torvalds 64031da177e4SLinus Torvalds *stpp = NULL; 64042dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 6405c0a5d93eSJ. Bruce Fields if (status) 6406c0a5d93eSJ. Bruce Fields return status; 6407e17f99b7STrond Myklebust stp = openlockstateid(s); 640858fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 64091da177e4SLinus Torvalds 6410e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 6411fd911011STrond Myklebust if (!status) 6412e17f99b7STrond Myklebust *stpp = stp; 6413fd911011STrond Myklebust else 6414fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 6415e17f99b7STrond Myklebust return status; 64161da177e4SLinus Torvalds } 64171da177e4SLinus Torvalds 64183320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 64193320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 6420c0a5d93eSJ. Bruce Fields { 6421c0a5d93eSJ. Bruce Fields __be32 status; 6422c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 64234cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 64241da177e4SLinus Torvalds 6425c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 64264cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 64270836f587SJ. Bruce Fields if (status) 64280836f587SJ. Bruce Fields return status; 64294cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 64304cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 6431feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 64324cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 6433c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 64344cbfc9f7STrond Myklebust } 64354cbfc9f7STrond Myklebust *stpp = stp; 64363a4f98bbSNeilBrown return nfs_ok; 64371da177e4SLinus Torvalds } 64381da177e4SLinus Torvalds 6439b37ad28bSAl Viro __be32 6440ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6441eb69853dSChristoph Hellwig union nfsd4_op_u *u) 64421da177e4SLinus Torvalds { 6443eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 6444b37ad28bSAl Viro __be32 status; 6445fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 6446dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 64473320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 64481da177e4SLinus Torvalds 6449a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 6450a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 64511da177e4SLinus Torvalds 6452ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 6453a8cddc5dSJ. Bruce Fields if (status) 6454a8cddc5dSJ. Bruce Fields return status; 64551da177e4SLinus Torvalds 64569072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 6457ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 64583320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 64599072d5c6SJ. Bruce Fields if (status) 64601da177e4SLinus Torvalds goto out; 6461fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 646268b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 646335a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 6464feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 64652585fc79STrond Myklebust goto put_stateid; 646635a92fe8SJeff Layton } 6467dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 64689767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 6469feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6470dd5e3fbcSChuck Lever trace_nfsd_open_confirm(oc->oc_seqid, &stp->st_stid.sc_stateid); 64712a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 647268b66e82SJ. Bruce Fields status = nfs_ok; 64732585fc79STrond Myklebust put_stateid: 64742585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 64751da177e4SLinus Torvalds out: 64769411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 64771da177e4SLinus Torvalds return status; 64781da177e4SLinus Torvalds } 64791da177e4SLinus Torvalds 64806409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 64811da177e4SLinus Torvalds { 648282c5ff1bSJeff Layton if (!test_access(access, stp)) 64836409a5a6SJ. Bruce Fields return; 648411b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 648582c5ff1bSJeff Layton clear_access(access, stp); 6486f197c271SJ. Bruce Fields } 64876409a5a6SJ. Bruce Fields 64886409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 64896409a5a6SJ. Bruce Fields { 64906409a5a6SJ. Bruce Fields switch (to_access) { 64916409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 64926409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 64936409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 64946409a5a6SJ. Bruce Fields break; 64956409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 64966409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 64976409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 64986409a5a6SJ. Bruce Fields break; 64996409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 65006409a5a6SJ. Bruce Fields break; 65016409a5a6SJ. Bruce Fields default: 6502063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 65031da177e4SLinus Torvalds } 65041da177e4SLinus Torvalds } 65051da177e4SLinus Torvalds 6506b37ad28bSAl Viro __be32 6507ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 6508eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 65091da177e4SLinus Torvalds { 6510eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 6511b37ad28bSAl Viro __be32 status; 6512dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 65133320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 65141da177e4SLinus Torvalds 6515a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 6516a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 65171da177e4SLinus Torvalds 6518c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 65192c8bd7e0SBenny Halevy if (od->od_deleg_want) 65202c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 65212c8bd7e0SBenny Halevy od->od_deleg_want); 65221da177e4SLinus Torvalds 6523c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 65243320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 65259072d5c6SJ. Bruce Fields if (status) 65261da177e4SLinus Torvalds goto out; 65271da177e4SLinus Torvalds status = nfserr_inval; 652882c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 6529c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 65301da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 65310667b1e9STrond Myklebust goto put_stateid; 65321da177e4SLinus Torvalds } 6533ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 6534c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 65351da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 65360667b1e9STrond Myklebust goto put_stateid; 65371da177e4SLinus Torvalds } 65386409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 6539ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 65409767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 65411da177e4SLinus Torvalds status = nfs_ok; 65420667b1e9STrond Myklebust put_stateid: 6543feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 65440667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 65451da177e4SLinus Torvalds out: 65469411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 65471da177e4SLinus Torvalds return status; 65481da177e4SLinus Torvalds } 65491da177e4SLinus Torvalds 6550f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 6551f7a4d872SJ. Bruce Fields { 6552acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 6553e8568739SJeff Layton bool unhashed; 6554d83017f9SJeff Layton LIST_HEAD(reaplist); 6555acf9295bSTrond Myklebust 65562c41beb0SJeff Layton spin_lock(&clp->cl_lock); 6557e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 6558acf9295bSTrond Myklebust 6559d83017f9SJeff Layton if (clp->cl_minorversion) { 6560e8568739SJeff Layton if (unhashed) 6561d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 6562d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6563d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6564d83017f9SJeff Layton } else { 6565d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6566d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6567e8568739SJeff Layton if (unhashed) 6568d3134b10SJeff Layton move_to_close_lru(s, clp->net); 656938c387b5SJ. Bruce Fields } 6570d83017f9SJeff Layton } 657138c387b5SJ. Bruce Fields 65721da177e4SLinus Torvalds /* 65731da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 65741da177e4SLinus Torvalds */ 6575b37ad28bSAl Viro __be32 6576ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6577eb69853dSChristoph Hellwig union nfsd4_op_u *u) 65781da177e4SLinus Torvalds { 6579eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 6580b37ad28bSAl Viro __be32 status; 6581dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 65823320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 65833320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 65841da177e4SLinus Torvalds 6585a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 6586a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 65871da177e4SLinus Torvalds 6588f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 6589f7a4d872SJ. Bruce Fields &close->cl_stateid, 6590f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 65913320fef1SStanislav Kinsbursky &stp, nn); 65929411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 65939072d5c6SJ. Bruce Fields if (status) 65941da177e4SLinus Torvalds goto out; 659515ca08d3STrond Myklebust 659615ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 6597bd2decacSJeff Layton 6598bd2decacSJeff Layton /* 6599bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 6600bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 6601bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 6602bd2decacSJeff Layton * that racing ops see that there was a state change. 6603bd2decacSJeff Layton */ 66049767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 66051da177e4SLinus Torvalds 6606f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 660715ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 66088a0b589dSTrond Myklebust 6609bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 6610bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 6611bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 6612bd2decacSJeff Layton * universally. 6613bd2decacSJeff Layton * 6614bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 6615bd2decacSJeff Layton */ 6616bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 6617fb500a7cSTrond Myklebust 66188a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 66198a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 66201da177e4SLinus Torvalds out: 66211da177e4SLinus Torvalds return status; 66221da177e4SLinus Torvalds } 66231da177e4SLinus Torvalds 6624b37ad28bSAl Viro __be32 6625ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6626eb69853dSChristoph Hellwig union nfsd4_op_u *u) 66271da177e4SLinus Torvalds { 6628eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 6629203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 6630203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 663138c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6632b37ad28bSAl Viro __be32 status; 66333320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 66341da177e4SLinus Torvalds 6635ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 6636203a8c8eSJ. Bruce Fields return status; 66371da177e4SLinus Torvalds 66382dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 663938c2f4b1SJ. Bruce Fields if (status) 6640203a8c8eSJ. Bruce Fields goto out; 664138c2f4b1SJ. Bruce Fields dp = delegstateid(s); 664203da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 6643203a8c8eSJ. Bruce Fields if (status) 6644fd911011STrond Myklebust goto put_stateid; 6645203a8c8eSJ. Bruce Fields 66463bd64a5bSJ. Bruce Fields destroy_delegation(dp); 6647fd911011STrond Myklebust put_stateid: 6648fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 66491da177e4SLinus Torvalds out: 66501da177e4SLinus Torvalds return status; 66511da177e4SLinus Torvalds } 66521da177e4SLinus Torvalds 665387df4de8SBenny Halevy /* last octet in a range */ 665487df4de8SBenny Halevy static inline u64 665587df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 665687df4de8SBenny Halevy { 665787df4de8SBenny Halevy u64 end; 665887df4de8SBenny Halevy 6659063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 666087df4de8SBenny Halevy end = start + len; 666187df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 666287df4de8SBenny Halevy } 666387df4de8SBenny Halevy 66641da177e4SLinus Torvalds /* 66651da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 66661da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 66671da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 66681da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 66691da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 66701da177e4SLinus Torvalds * the VFS, but this is a very deep change! 66711da177e4SLinus Torvalds */ 66721da177e4SLinus Torvalds static inline void 66731da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 66741da177e4SLinus Torvalds { 66751da177e4SLinus Torvalds if (lock->fl_start < 0) 66761da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 66771da177e4SLinus Torvalds if (lock->fl_end < 0) 66781da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 66791da177e4SLinus Torvalds } 66801da177e4SLinus Torvalds 6681cae80b30SJeff Layton static fl_owner_t 668235aff067SChuck Lever nfsd4_lm_get_owner(fl_owner_t owner) 6683aef9583bSKinglong Mee { 6684cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6685cae80b30SJeff Layton 6686cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 6687cae80b30SJeff Layton return owner; 6688aef9583bSKinglong Mee } 6689aef9583bSKinglong Mee 6690cae80b30SJeff Layton static void 669135aff067SChuck Lever nfsd4_lm_put_owner(fl_owner_t owner) 6692aef9583bSKinglong Mee { 6693cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 6694aef9583bSKinglong Mee 6695cae80b30SJeff Layton if (lo) 6696aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 6697aef9583bSKinglong Mee } 6698aef9583bSKinglong Mee 669976d348faSJeff Layton static void 670076d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 670176d348faSJeff Layton { 670276d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 670376d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 670476d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 670576d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 670676d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 670776d348faSJeff Layton bool queue = false; 670876d348faSJeff Layton 67097919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 67100cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 671176d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 671276d348faSJeff Layton list_del_init(&nbl->nbl_list); 67137919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 671476d348faSJeff Layton queue = true; 671576d348faSJeff Layton } 67160cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 671776d348faSJeff Layton 67182cde7f81SChuck Lever if (queue) { 67192cde7f81SChuck Lever trace_nfsd_cb_notify_lock(lo, nbl); 672076d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 672176d348faSJeff Layton } 67222cde7f81SChuck Lever } 672376d348faSJeff Layton 67247b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 672576d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 672635aff067SChuck Lever .lm_get_owner = nfsd4_lm_get_owner, 672735aff067SChuck Lever .lm_put_owner = nfsd4_lm_put_owner, 6728d5b9026aSNeilBrown }; 67291da177e4SLinus Torvalds 67301da177e4SLinus Torvalds static inline void 67311da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 67321da177e4SLinus Torvalds { 6733fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 67341da177e4SLinus Torvalds 6735d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 6736fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 67376f4859b8SJ. Bruce Fields xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner, 67386f4859b8SJ. Bruce Fields GFP_KERNEL); 67397c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 67407c13f344SJ. Bruce Fields /* We just don't care that much */ 67417c13f344SJ. Bruce Fields goto nevermind; 6742fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 6743d5b9026aSNeilBrown } else { 67447c13f344SJ. Bruce Fields nevermind: 67457c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 67467c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 6747d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 6748d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 67491da177e4SLinus Torvalds } 67501da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 675187df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 675287df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 67531da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 67541da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 67551da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 67561da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 67571da177e4SLinus Torvalds } 67581da177e4SLinus Torvalds 6759fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6760c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 67611da177e4SLinus Torvalds { 6762d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 6763b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 67641da177e4SLinus Torvalds 67650a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 67660a880a28STrond Myklebust 6767d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 6768d4f0489fSTrond Myklebust so_strhash) { 6769b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 6770b3c32bcdSTrond Myklebust continue; 6771b5971afaSKinglong Mee if (same_owner_str(so, owner)) 6772b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 67731da177e4SLinus Torvalds } 67741da177e4SLinus Torvalds return NULL; 67751da177e4SLinus Torvalds } 67761da177e4SLinus Torvalds 6777c58c6610STrond Myklebust static struct nfs4_lockowner * 6778c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 6779c58c6610STrond Myklebust { 6780c58c6610STrond Myklebust struct nfs4_lockowner *lo; 6781c58c6610STrond Myklebust 6782d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6783c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 6784d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6785c58c6610STrond Myklebust return lo; 6786c58c6610STrond Myklebust } 6787c58c6610STrond Myklebust 67888f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 67898f4b54c5SJeff Layton { 6790c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 67918f4b54c5SJeff Layton } 67928f4b54c5SJeff Layton 67936b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 67946b180f0bSJeff Layton { 67956b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 67966b180f0bSJeff Layton 67976b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 67986b180f0bSJeff Layton } 67996b180f0bSJeff Layton 68006b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 68018f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 68026b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 68036b180f0bSJeff Layton }; 68046b180f0bSJeff Layton 68051da177e4SLinus Torvalds /* 68061da177e4SLinus Torvalds * Alloc a lock owner structure. 68071da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 680825985edcSLucas De Marchi * occurred. 68091da177e4SLinus Torvalds * 681016bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 68111da177e4SLinus Torvalds */ 6812fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 6813c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 6814c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 6815c58c6610STrond Myklebust struct nfsd4_lock *lock) 6816c58c6610STrond Myklebust { 6817c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 68181da177e4SLinus Torvalds 6819fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 6820fe0750e5SJ. Bruce Fields if (!lo) 68211da177e4SLinus Torvalds return NULL; 682276d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 6823fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 6824fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 68255db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 68266b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 6827d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 6828c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 6829c58c6610STrond Myklebust if (ret == NULL) { 6830c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 6831d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 6832c58c6610STrond Myklebust ret = lo; 6833c58c6610STrond Myklebust } else 6834d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 6835d50ffdedSKinglong Mee 6836d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 6837340f0ba1SJ. Bruce Fields return ret; 68381da177e4SLinus Torvalds } 68391da177e4SLinus Torvalds 6840fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 6841a451b123STrond Myklebust find_lock_stateid(const struct nfs4_lockowner *lo, 6842a451b123STrond Myklebust const struct nfs4_ol_stateid *ost) 6843fd1fd685STrond Myklebust { 6844fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 6845fd1fd685STrond Myklebust 6846a451b123STrond Myklebust lockdep_assert_held(&ost->st_stid.sc_client->cl_lock); 6847fd1fd685STrond Myklebust 6848a451b123STrond Myklebust /* If ost is not hashed, ost->st_locks will not be valid */ 6849a451b123STrond Myklebust if (!nfs4_ol_stateid_unhashed(ost)) 6850a451b123STrond Myklebust list_for_each_entry(lst, &ost->st_locks, st_locks) { 6851a451b123STrond Myklebust if (lst->st_stateowner == &lo->lo_owner) { 6852fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 6853fd1fd685STrond Myklebust return lst; 6854fd1fd685STrond Myklebust } 6855fd1fd685STrond Myklebust } 6856fd1fd685STrond Myklebust return NULL; 6857fd1fd685STrond Myklebust } 6858fd1fd685STrond Myklebust 6859beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 6860356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 6861356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 6862f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 68631da177e4SLinus Torvalds { 6864d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 6865beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 68661da177e4SLinus Torvalds 6867beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 68684f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 6869beeca19cSTrond Myklebust retry: 6870beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 6871a451b123STrond Myklebust if (nfs4_ol_stateid_unhashed(open_stp)) 6872a451b123STrond Myklebust goto out_close; 6873a451b123STrond Myklebust retstp = find_lock_stateid(lo, open_stp); 6874beeca19cSTrond Myklebust if (retstp) 6875a451b123STrond Myklebust goto out_found; 6876a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 68773abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 6878b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 687913cd2184SNeilBrown get_nfs4_file(fp); 688011b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 68810997b173SJ. Bruce Fields stp->st_access_bmap = 0; 68821da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 68834c4cd222SNeilBrown stp->st_openstp = open_stp; 6884a451b123STrond Myklebust spin_lock(&fp->fi_lock); 68853c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 68861c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 68871d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 68881d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 6889beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 6890a451b123STrond Myklebust return stp; 6891a451b123STrond Myklebust out_found: 6892a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 6893beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 6894beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 6895beeca19cSTrond Myklebust goto retry; 6896beeca19cSTrond Myklebust } 6897beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 6898beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 6899a451b123STrond Myklebust return retstp; 6900a451b123STrond Myklebust out_close: 6901a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 6902a451b123STrond Myklebust mutex_unlock(&stp->st_mutex); 6903a451b123STrond Myklebust return NULL; 69041da177e4SLinus Torvalds } 69051da177e4SLinus Torvalds 6906c53530daSJeff Layton static struct nfs4_ol_stateid * 6907356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 6908356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 6909356a95ecSJeff Layton bool *new) 6910356a95ecSJeff Layton { 6911356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 6912356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 6913356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 6914356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 6915356a95ecSJeff Layton 6916beeca19cSTrond Myklebust *new = false; 6917356a95ecSJeff Layton spin_lock(&clp->cl_lock); 6918a451b123STrond Myklebust lst = find_lock_stateid(lo, ost); 6919356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 6920beeca19cSTrond Myklebust if (lst != NULL) { 6921beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 6922beeca19cSTrond Myklebust goto out; 6923beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 6924beeca19cSTrond Myklebust } 6925d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 6926356a95ecSJeff Layton if (ns == NULL) 6927356a95ecSJeff Layton return NULL; 6928356a95ecSJeff Layton 6929beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 6930beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 6931356a95ecSJeff Layton *new = true; 6932beeca19cSTrond Myklebust else 6933356a95ecSJeff Layton nfs4_put_stid(ns); 6934beeca19cSTrond Myklebust out: 6935356a95ecSJeff Layton return lst; 6936356a95ecSJeff Layton } 6937c53530daSJeff Layton 6938fd39ca9aSNeilBrown static int 69391da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 69401da177e4SLinus Torvalds { 694187df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 6942e7969315SKinglong Mee (length > ~offset))); 69431da177e4SLinus Torvalds } 69441da177e4SLinus Torvalds 6945dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 69460997b173SJ. Bruce Fields { 694711b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 69480997b173SJ. Bruce Fields 69497214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 69507214e860SJeff Layton 695182c5ff1bSJeff Layton if (test_access(access, lock_stp)) 69520997b173SJ. Bruce Fields return; 695312659651SJeff Layton __nfs4_file_get_access(fp, access); 695482c5ff1bSJeff Layton set_access(access, lock_stp); 69550997b173SJ. Bruce Fields } 69560997b173SJ. Bruce Fields 6957356a95ecSJeff Layton static __be32 6958356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 6959356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 6960356a95ecSJeff Layton struct nfsd4_lock *lock, 6961dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 696264a284d0SJ. Bruce Fields { 69635db1c03fSJeff Layton __be32 status; 696411b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 696564a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 696664a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 69672b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 696864a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 6969dd257933SJeff Layton struct nfs4_ol_stateid *lst; 697064a284d0SJ. Bruce Fields unsigned int strhashval; 697164a284d0SJ. Bruce Fields 6972c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 6973c53530daSJeff Layton if (!lo) { 697476f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 697564a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 697664a284d0SJ. Bruce Fields if (lo == NULL) 697764a284d0SJ. Bruce Fields return nfserr_jukebox; 6978c53530daSJeff Layton } else { 6979c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 69805db1c03fSJeff Layton status = nfserr_bad_seqid; 6981c53530daSJeff Layton if (!cstate->minorversion && 6982c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 69835db1c03fSJeff Layton goto out; 6984c53530daSJeff Layton } 6985c53530daSJeff Layton 6986dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 6987dd257933SJeff Layton if (lst == NULL) { 69885db1c03fSJeff Layton status = nfserr_jukebox; 69895db1c03fSJeff Layton goto out; 699064a284d0SJ. Bruce Fields } 6991dd257933SJeff Layton 69925db1c03fSJeff Layton status = nfs_ok; 6993dd257933SJeff Layton *plst = lst; 69945db1c03fSJeff Layton out: 69955db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 69965db1c03fSJeff Layton return status; 699764a284d0SJ. Bruce Fields } 699864a284d0SJ. Bruce Fields 69991da177e4SLinus Torvalds /* 70001da177e4SLinus Torvalds * LOCK operation 70011da177e4SLinus Torvalds */ 7002b37ad28bSAl Viro __be32 7003ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7004eb69853dSChristoph Hellwig union nfsd4_op_u *u) 70051da177e4SLinus Torvalds { 7006eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 7007fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 7008fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 70093d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 70100667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 70117214e860SJeff Layton struct nfs4_file *fp; 7012eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 701376d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 701421179d81SJeff Layton struct file_lock *file_lock = NULL; 701521179d81SJeff Layton struct file_lock *conflock = NULL; 7016b37ad28bSAl Viro __be32 status = 0; 7017b34f27aaSJ. Bruce Fields int lkflg; 7018b8dd7b9aSAl Viro int err; 70195db1c03fSJeff Layton bool new = false; 702076d348faSJeff Layton unsigned char fl_type; 702176d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 70223320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 70233320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 70241da177e4SLinus Torvalds 70251da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 70261da177e4SLinus Torvalds (long long) lock->lk_offset, 70271da177e4SLinus Torvalds (long long) lock->lk_length); 70281da177e4SLinus Torvalds 70291da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 70301da177e4SLinus Torvalds return nfserr_inval; 70311da177e4SLinus Torvalds 7032ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 70338837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 7034a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 7035a6f6ef2fSAndy Adamson return status; 7036a6f6ef2fSAndy Adamson } 7037a6f6ef2fSAndy Adamson 70381da177e4SLinus Torvalds if (lock->lk_is_new) { 7039684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 7040684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 704176f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 7042ec59659bSJ. Bruce Fields &cstate->clp->cl_clientid, 7043684e5638SJ. Bruce Fields sizeof(clientid_t)); 7044684e5638SJ. Bruce Fields 70451da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 7046c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 70471da177e4SLinus Torvalds lock->lk_new_open_seqid, 70481da177e4SLinus Torvalds &lock->lk_new_open_stateid, 70493320fef1SStanislav Kinsbursky &open_stp, nn); 705037515177SNeilBrown if (status) 70511da177e4SLinus Torvalds goto out; 7052feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 7053fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 7054b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 7055684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 705676f6c9e1SKinglong Mee &lock->lk_new_clientid)) 7057b34f27aaSJ. Bruce Fields goto out; 705864a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 70595db1c03fSJeff Layton &lock_stp, &new); 70603d0fabd5STrond Myklebust } else { 7061dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 70621da177e4SLinus Torvalds lock->lk_old_lock_seqid, 70631da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 70643320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 70653d0fabd5STrond Myklebust } 70661da177e4SLinus Torvalds if (status) 70671da177e4SLinus Torvalds goto out; 7068fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 70691da177e4SLinus Torvalds 7070b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 7071b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 7072b34f27aaSJ. Bruce Fields if (status) 7073b34f27aaSJ. Bruce Fields goto out; 7074b34f27aaSJ. Bruce Fields 70750dd395dcSNeilBrown status = nfserr_grace; 70763320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 70770dd395dcSNeilBrown goto out; 70780dd395dcSNeilBrown status = nfserr_no_grace; 70793320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 70800dd395dcSNeilBrown goto out; 70810dd395dcSNeilBrown 7082bb0a55bbSJ. Bruce Fields if (lock->lk_reclaim) 7083bb0a55bbSJ. Bruce Fields fl_flags |= FL_RECLAIM; 7084bb0a55bbSJ. Bruce Fields 708511b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 70861da177e4SLinus Torvalds switch (lock->lk_type) { 70871da177e4SLinus Torvalds case NFS4_READW_LT: 708840595cdcSJ. Bruce Fields if (nfsd4_has_session(cstate)) 708976d348faSJeff Layton fl_flags |= FL_SLEEP; 7090df561f66SGustavo A. R. Silva fallthrough; 709176d348faSJeff Layton case NFS4_READ_LT: 70927214e860SJeff Layton spin_lock(&fp->fi_lock); 7093eb82dd39SJeff Layton nf = find_readable_file_locked(fp); 7094eb82dd39SJeff Layton if (nf) 70950997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 70967214e860SJeff Layton spin_unlock(&fp->fi_lock); 709776d348faSJeff Layton fl_type = F_RDLCK; 70981da177e4SLinus Torvalds break; 70991da177e4SLinus Torvalds case NFS4_WRITEW_LT: 710040595cdcSJ. Bruce Fields if (nfsd4_has_session(cstate)) 710176d348faSJeff Layton fl_flags |= FL_SLEEP; 7102df561f66SGustavo A. R. Silva fallthrough; 710376d348faSJeff Layton case NFS4_WRITE_LT: 71047214e860SJeff Layton spin_lock(&fp->fi_lock); 7105eb82dd39SJeff Layton nf = find_writeable_file_locked(fp); 7106eb82dd39SJeff Layton if (nf) 71070997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 71087214e860SJeff Layton spin_unlock(&fp->fi_lock); 710976d348faSJeff Layton fl_type = F_WRLCK; 71101da177e4SLinus Torvalds break; 71111da177e4SLinus Torvalds default: 71121da177e4SLinus Torvalds status = nfserr_inval; 71131da177e4SLinus Torvalds goto out; 71141da177e4SLinus Torvalds } 711576d348faSJeff Layton 7116eb82dd39SJeff Layton if (!nf) { 7117f9d7562fSJ. Bruce Fields status = nfserr_openmode; 7118f9d7562fSJ. Bruce Fields goto out; 7119f9d7562fSJ. Bruce Fields } 7120aef9583bSKinglong Mee 712140595cdcSJ. Bruce Fields /* 712240595cdcSJ. Bruce Fields * Most filesystems with their own ->lock operations will block 712340595cdcSJ. Bruce Fields * the nfsd thread waiting to acquire the lock. That leads to 712440595cdcSJ. Bruce Fields * deadlocks (we don't want every nfsd thread tied up waiting 712540595cdcSJ. Bruce Fields * for file locks), so don't attempt blocking lock notifications 712640595cdcSJ. Bruce Fields * on those filesystems: 712740595cdcSJ. Bruce Fields */ 712840595cdcSJ. Bruce Fields if (nf->nf_file->f_op->lock) 712940595cdcSJ. Bruce Fields fl_flags &= ~FL_SLEEP; 713040595cdcSJ. Bruce Fields 713176d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 713276d348faSJeff Layton if (!nbl) { 713376d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 713476d348faSJeff Layton status = nfserr_jukebox; 713576d348faSJeff Layton goto out; 713676d348faSJeff Layton } 713776d348faSJeff Layton 713876d348faSJeff Layton file_lock = &nbl->nbl_lock; 713976d348faSJeff Layton file_lock->fl_type = fl_type; 7140aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 714121179d81SJeff Layton file_lock->fl_pid = current->tgid; 7142eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 714376d348faSJeff Layton file_lock->fl_flags = fl_flags; 714421179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 714521179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 714621179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 714721179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 71481da177e4SLinus Torvalds 714921179d81SJeff Layton conflock = locks_alloc_lock(); 715021179d81SJeff Layton if (!conflock) { 715121179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 715221179d81SJeff Layton status = nfserr_jukebox; 715321179d81SJeff Layton goto out; 715421179d81SJeff Layton } 71551da177e4SLinus Torvalds 715676d348faSJeff Layton if (fl_flags & FL_SLEEP) { 715720b7d86fSArnd Bergmann nbl->nbl_time = ktime_get_boottime_seconds(); 71580cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 715976d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 71607919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 716147446d74SVasily Averin kref_get(&nbl->nbl_kref); 71620cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 716376d348faSJeff Layton } 716476d348faSJeff Layton 7165eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, conflock); 716676d348faSJeff Layton switch (err) { 71671da177e4SLinus Torvalds case 0: /* success! */ 71689767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 7169b8dd7b9aSAl Viro status = 0; 717003f318caSJ. Bruce Fields if (lock->lk_reclaim) 717103f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 7172eb76b3fdSAndy Adamson break; 717376d348faSJeff Layton case FILE_LOCK_DEFERRED: 717447446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 717576d348faSJeff Layton nbl = NULL; 7176df561f66SGustavo A. R. Silva fallthrough; 717776d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 7178eb76b3fdSAndy Adamson status = nfserr_denied; 7179eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 718021179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 7181eb76b3fdSAndy Adamson break; 718276d348faSJeff Layton case -EDEADLK: 71831da177e4SLinus Torvalds status = nfserr_deadlock; 7184eb76b3fdSAndy Adamson break; 71851da177e4SLinus Torvalds default: 7186fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 71873e772463SJ. Bruce Fields status = nfserrno(err); 7188eb76b3fdSAndy Adamson break; 71891da177e4SLinus Torvalds } 71901da177e4SLinus Torvalds out: 719176d348faSJeff Layton if (nbl) { 719276d348faSJeff Layton /* dequeue it if we queued it before */ 719376d348faSJeff Layton if (fl_flags & FL_SLEEP) { 71940cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 719547446d74SVasily Averin if (!list_empty(&nbl->nbl_list) && 719647446d74SVasily Averin !list_empty(&nbl->nbl_lru)) { 719776d348faSJeff Layton list_del_init(&nbl->nbl_list); 71987919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 719947446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 720047446d74SVasily Averin } 720147446d74SVasily Averin /* nbl can use one of lists to be linked to reaplist */ 72020cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 720376d348faSJeff Layton } 720476d348faSJeff Layton free_blocked_lock(nbl); 720576d348faSJeff Layton } 7206eb82dd39SJeff Layton if (nf) 7207eb82dd39SJeff Layton nfsd_file_put(nf); 72085db1c03fSJeff Layton if (lock_stp) { 72095db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 72105db1c03fSJeff Layton if (cstate->replay_owner && 72115db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 72125db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 72135db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 72145db1c03fSJeff Layton 72155db1c03fSJeff Layton /* 72165db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 72175db1c03fSJeff Layton * returning an error, then just go ahead and release it. 72185db1c03fSJeff Layton */ 721925020720SJ. Bruce Fields if (status && new) 72205db1c03fSJeff Layton release_lock_stateid(lock_stp); 7221beeca19cSTrond Myklebust 7222beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 72235db1c03fSJeff Layton 72243d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 72255db1c03fSJeff Layton } 72260667b1e9STrond Myklebust if (open_stp) 72270667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 72289411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 722921179d81SJeff Layton if (conflock) 723021179d81SJeff Layton locks_free_lock(conflock); 72311da177e4SLinus Torvalds return status; 72321da177e4SLinus Torvalds } 72331da177e4SLinus Torvalds 72341da177e4SLinus Torvalds /* 723555ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 723655ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 72370bcc7ca4SJ. Bruce Fields * vfs_test_lock. 723855ef1274SJ. Bruce Fields */ 723904da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 724055ef1274SJ. Bruce Fields { 72416b556ca2SJeff Layton struct nfsd_file *nf; 7242217fd6f6SJ. Bruce Fields __be32 err; 7243217fd6f6SJ. Bruce Fields 7244217fd6f6SJ. Bruce Fields err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); 7245217fd6f6SJ. Bruce Fields if (err) 7246217fd6f6SJ. Bruce Fields return err; 7247217fd6f6SJ. Bruce Fields fh_lock(fhp); /* to block new leases till after test_lock: */ 7248217fd6f6SJ. Bruce Fields err = nfserrno(nfsd_open_break_lease(fhp->fh_dentry->d_inode, 7249217fd6f6SJ. Bruce Fields NFSD_MAY_READ)); 7250217fd6f6SJ. Bruce Fields if (err) 7251217fd6f6SJ. Bruce Fields goto out; 72520bcc7ca4SJ. Bruce Fields lock->fl_file = nf->nf_file; 72536b556ca2SJeff Layton err = nfserrno(vfs_test_lock(nf->nf_file, lock)); 72540bcc7ca4SJ. Bruce Fields lock->fl_file = NULL; 7255217fd6f6SJ. Bruce Fields out: 7256217fd6f6SJ. Bruce Fields fh_unlock(fhp); 72576b556ca2SJeff Layton nfsd_file_put(nf); 725855ef1274SJ. Bruce Fields return err; 725955ef1274SJ. Bruce Fields } 726055ef1274SJ. Bruce Fields 726155ef1274SJ. Bruce Fields /* 72621da177e4SLinus Torvalds * LOCKT operation 72631da177e4SLinus Torvalds */ 7264b37ad28bSAl Viro __be32 7265ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7266eb69853dSChristoph Hellwig union nfsd4_op_u *u) 72671da177e4SLinus Torvalds { 7268eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 726921179d81SJeff Layton struct file_lock *file_lock = NULL; 72705db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 7271b37ad28bSAl Viro __be32 status; 72727f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 72731da177e4SLinus Torvalds 72745ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 72751da177e4SLinus Torvalds return nfserr_grace; 72761da177e4SLinus Torvalds 72771da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 72781da177e4SLinus Torvalds return nfserr_inval; 72791da177e4SLinus Torvalds 72809b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 7281f71475baSJ. Bruce Fields status = set_client(&lockt->lt_clientid, cstate, nn); 72829b2ef62bSJ. Bruce Fields if (status) 72831da177e4SLinus Torvalds goto out; 72849b2ef62bSJ. Bruce Fields } 72851da177e4SLinus Torvalds 728675c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 72871da177e4SLinus Torvalds goto out; 72881da177e4SLinus Torvalds 728921179d81SJeff Layton file_lock = locks_alloc_lock(); 729021179d81SJeff Layton if (!file_lock) { 729121179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 729221179d81SJeff Layton status = nfserr_jukebox; 729321179d81SJeff Layton goto out; 729421179d81SJeff Layton } 72956cd90662SKinglong Mee 72961da177e4SLinus Torvalds switch (lockt->lt_type) { 72971da177e4SLinus Torvalds case NFS4_READ_LT: 72981da177e4SLinus Torvalds case NFS4_READW_LT: 729921179d81SJeff Layton file_lock->fl_type = F_RDLCK; 73001da177e4SLinus Torvalds break; 73011da177e4SLinus Torvalds case NFS4_WRITE_LT: 73021da177e4SLinus Torvalds case NFS4_WRITEW_LT: 730321179d81SJeff Layton file_lock->fl_type = F_WRLCK; 73041da177e4SLinus Torvalds break; 73051da177e4SLinus Torvalds default: 73062fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 73071da177e4SLinus Torvalds status = nfserr_inval; 73081da177e4SLinus Torvalds goto out; 73091da177e4SLinus Torvalds } 73101da177e4SLinus Torvalds 7311c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 7312fe0750e5SJ. Bruce Fields if (lo) 731321179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 731421179d81SJeff Layton file_lock->fl_pid = current->tgid; 731521179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 73161da177e4SLinus Torvalds 731721179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 731821179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 73191da177e4SLinus Torvalds 732021179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 73211da177e4SLinus Torvalds 732221179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 732304da6e9dSAl Viro if (status) 7324fd85b817SMarc Eshel goto out; 732504da6e9dSAl Viro 732621179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 73271da177e4SLinus Torvalds status = nfserr_denied; 732821179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 73291da177e4SLinus Torvalds } 73301da177e4SLinus Torvalds out: 73315db1c03fSJeff Layton if (lo) 73325db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 733321179d81SJeff Layton if (file_lock) 733421179d81SJeff Layton locks_free_lock(file_lock); 73351da177e4SLinus Torvalds return status; 73361da177e4SLinus Torvalds } 73371da177e4SLinus Torvalds 7338b37ad28bSAl Viro __be32 7339ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7340eb69853dSChristoph Hellwig union nfsd4_op_u *u) 73411da177e4SLinus Torvalds { 7342eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 7343dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 7344eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 734521179d81SJeff Layton struct file_lock *file_lock = NULL; 7346b37ad28bSAl Viro __be32 status; 7347b8dd7b9aSAl Viro int err; 73483320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 73491da177e4SLinus Torvalds 73501da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 73511da177e4SLinus Torvalds (long long) locku->lu_offset, 73521da177e4SLinus Torvalds (long long) locku->lu_length); 73531da177e4SLinus Torvalds 73541da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 73551da177e4SLinus Torvalds return nfserr_inval; 73561da177e4SLinus Torvalds 73579072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 73583320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 73593320fef1SStanislav Kinsbursky &stp, nn); 73609072d5c6SJ. Bruce Fields if (status) 73611da177e4SLinus Torvalds goto out; 7362eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 7363eb82dd39SJeff Layton if (!nf) { 7364f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 7365858cc573STrond Myklebust goto put_stateid; 7366f9d7562fSJ. Bruce Fields } 736721179d81SJeff Layton file_lock = locks_alloc_lock(); 736821179d81SJeff Layton if (!file_lock) { 736921179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 737021179d81SJeff Layton status = nfserr_jukebox; 7371eb82dd39SJeff Layton goto put_file; 737221179d81SJeff Layton } 73736cd90662SKinglong Mee 737421179d81SJeff Layton file_lock->fl_type = F_UNLCK; 7375aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 737621179d81SJeff Layton file_lock->fl_pid = current->tgid; 7377eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 737821179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 737921179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 738021179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 73811da177e4SLinus Torvalds 738221179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 738321179d81SJeff Layton locku->lu_length); 738421179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 73851da177e4SLinus Torvalds 7386eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, NULL); 7387b8dd7b9aSAl Viro if (err) { 7388fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 73891da177e4SLinus Torvalds goto out_nfserr; 73901da177e4SLinus Torvalds } 73919767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 7392eb82dd39SJeff Layton put_file: 7393eb82dd39SJeff Layton nfsd_file_put(nf); 7394858cc573STrond Myklebust put_stateid: 7395feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 7396858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 73971da177e4SLinus Torvalds out: 73989411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 739921179d81SJeff Layton if (file_lock) 740021179d81SJeff Layton locks_free_lock(file_lock); 74011da177e4SLinus Torvalds return status; 74021da177e4SLinus Torvalds 74031da177e4SLinus Torvalds out_nfserr: 7404b8dd7b9aSAl Viro status = nfserrno(err); 7405eb82dd39SJeff Layton goto put_file; 74061da177e4SLinus Torvalds } 74071da177e4SLinus Torvalds 74081da177e4SLinus Torvalds /* 74091da177e4SLinus Torvalds * returns 7410f9c00c3aSJeff Layton * true: locks held by lockowner 7411f9c00c3aSJeff Layton * false: no locks held by lockowner 74121da177e4SLinus Torvalds */ 7413f9c00c3aSJeff Layton static bool 7414f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 74151da177e4SLinus Torvalds { 7416bd61e0a9SJeff Layton struct file_lock *fl; 7417f9c00c3aSJeff Layton int status = false; 7418eb82dd39SJeff Layton struct nfsd_file *nf = find_any_file(fp); 7419f9c00c3aSJeff Layton struct inode *inode; 7420bd61e0a9SJeff Layton struct file_lock_context *flctx; 7421f9c00c3aSJeff Layton 7422eb82dd39SJeff Layton if (!nf) { 7423f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 7424f9c00c3aSJeff Layton WARN_ON_ONCE(1); 7425f9c00c3aSJeff Layton return status; 7426f9c00c3aSJeff Layton } 7427f9c00c3aSJeff Layton 7428eb82dd39SJeff Layton inode = locks_inode(nf->nf_file); 7429bd61e0a9SJeff Layton flctx = inode->i_flctx; 74301da177e4SLinus Torvalds 7431bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 74326109c850SJeff Layton spin_lock(&flctx->flc_lock); 7433bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 7434bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 7435f9c00c3aSJeff Layton status = true; 7436f9c00c3aSJeff Layton break; 74371da177e4SLinus Torvalds } 7438796dadfdSJ. Bruce Fields } 74396109c850SJeff Layton spin_unlock(&flctx->flc_lock); 7440bd61e0a9SJeff Layton } 7441eb82dd39SJeff Layton nfsd_file_put(nf); 74421da177e4SLinus Torvalds return status; 74431da177e4SLinus Torvalds } 74441da177e4SLinus Torvalds 7445b37ad28bSAl Viro __be32 7446b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 7447b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 7448eb69853dSChristoph Hellwig union nfsd4_op_u *u) 74491da177e4SLinus Torvalds { 7450eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 74511da177e4SLinus Torvalds clientid_t *clid = &rlockowner->rl_clientid; 7452882e9d25SJeff Layton struct nfs4_stateowner *sop; 7453882e9d25SJeff Layton struct nfs4_lockowner *lo = NULL; 7454dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 74551da177e4SLinus Torvalds struct xdr_netobj *owner = &rlockowner->rl_owner; 7456d4f0489fSTrond Myklebust unsigned int hashval = ownerstr_hashval(owner); 7457b37ad28bSAl Viro __be32 status; 74587f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 7459c58c6610STrond Myklebust struct nfs4_client *clp; 746088584818SChuck Lever LIST_HEAD (reaplist); 74611da177e4SLinus Torvalds 74621da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 74631da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 74641da177e4SLinus Torvalds 7465f71475baSJ. Bruce Fields status = set_client(clid, cstate, nn); 74669b2ef62bSJ. Bruce Fields if (status) 746751f5e783STrond Myklebust return status; 74689b2ef62bSJ. Bruce Fields 7469d4f0489fSTrond Myklebust clp = cstate->clp; 7470fd44907cSJeff Layton /* Find the matching lock stateowner */ 7471d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7472882e9d25SJeff Layton list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], 7473d4f0489fSTrond Myklebust so_strhash) { 7474882e9d25SJeff Layton 7475882e9d25SJeff Layton if (sop->so_is_open_owner || !same_owner_str(sop, owner)) 747616bfdaafSJ. Bruce Fields continue; 7477882e9d25SJeff Layton 7478882e9d25SJeff Layton /* see if there are still any locks associated with it */ 7479882e9d25SJeff Layton lo = lockowner(sop); 7480882e9d25SJeff Layton list_for_each_entry(stp, &sop->so_stateids, st_perstateowner) { 7481882e9d25SJeff Layton if (check_for_locks(stp->st_stid.sc_file, lo)) { 7482882e9d25SJeff Layton status = nfserr_locks_held; 7483882e9d25SJeff Layton spin_unlock(&clp->cl_lock); 748451f5e783STrond Myklebust return status; 7485882e9d25SJeff Layton } 7486882e9d25SJeff Layton } 7487882e9d25SJeff Layton 7488b5971afaSKinglong Mee nfs4_get_stateowner(sop); 7489fd44907cSJeff Layton break; 7490fd44907cSJeff Layton } 749188584818SChuck Lever if (!lo) { 7492d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 749388584818SChuck Lever return status; 749488584818SChuck Lever } 749588584818SChuck Lever 749688584818SChuck Lever unhash_lockowner_locked(lo); 749788584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 749888584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 749988584818SChuck Lever struct nfs4_ol_stateid, 750088584818SChuck Lever st_perstateowner); 750188584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 750288584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 750388584818SChuck Lever } 750488584818SChuck Lever spin_unlock(&clp->cl_lock); 750588584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 750668ef3bc3SJeff Layton remove_blocked_locks(lo); 750788584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 750888584818SChuck Lever 75091da177e4SLinus Torvalds return status; 75101da177e4SLinus Torvalds } 75111da177e4SLinus Torvalds 75121da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 7513a55370a3SNeilBrown alloc_reclaim(void) 75141da177e4SLinus Torvalds { 7515a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 75161da177e4SLinus Torvalds } 75171da177e4SLinus Torvalds 75180ce0c2b5SJeff Layton bool 75196b189105SScott Mayhew nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) 7520c7b9a459SNeilBrown { 75210ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 7522c7b9a459SNeilBrown 752352e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 75240ce0c2b5SJeff Layton return (crp && crp->cr_clp); 7525c7b9a459SNeilBrown } 7526c7b9a459SNeilBrown 75271da177e4SLinus Torvalds /* 75281da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 75296b189105SScott Mayhew * 75306b189105SScott Mayhew * The caller is responsible for freeing name.data if NULL is returned (it 75316b189105SScott Mayhew * will be freed in nfs4_remove_reclaim_record in the normal case). 75321da177e4SLinus Torvalds */ 7533772a9bbbSJeff Layton struct nfs4_client_reclaim * 75346ee95d1cSScott Mayhew nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, 75356ee95d1cSScott Mayhew struct nfsd_net *nn) 75361da177e4SLinus Torvalds { 75371da177e4SLinus Torvalds unsigned int strhashval; 7538772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 75391da177e4SLinus Torvalds 7540a55370a3SNeilBrown crp = alloc_reclaim(); 7541772a9bbbSJeff Layton if (crp) { 7542a55370a3SNeilBrown strhashval = clientstr_hashval(name); 75431da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 754452e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 75456b189105SScott Mayhew crp->cr_name.data = name.data; 75466b189105SScott Mayhew crp->cr_name.len = name.len; 75476ee95d1cSScott Mayhew crp->cr_princhash.data = princhash.data; 75486ee95d1cSScott Mayhew crp->cr_princhash.len = princhash.len; 75490ce0c2b5SJeff Layton crp->cr_clp = NULL; 755052e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 7551772a9bbbSJeff Layton } 7552772a9bbbSJeff Layton return crp; 75531da177e4SLinus Torvalds } 75541da177e4SLinus Torvalds 75552a4317c5SJeff Layton void 755652e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 7557ce30e539SJeff Layton { 7558ce30e539SJeff Layton list_del(&crp->cr_strhash); 75596b189105SScott Mayhew kfree(crp->cr_name.data); 75606ee95d1cSScott Mayhew kfree(crp->cr_princhash.data); 7561ce30e539SJeff Layton kfree(crp); 756252e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 7563ce30e539SJeff Layton } 7564ce30e539SJeff Layton 7565ce30e539SJeff Layton void 756652e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 75671da177e4SLinus Torvalds { 75681da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 75691da177e4SLinus Torvalds int i; 75701da177e4SLinus Torvalds 75711da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 757252e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 757352e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 75741da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 757552e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 75761da177e4SLinus Torvalds } 75771da177e4SLinus Torvalds } 7578063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 75791da177e4SLinus Torvalds } 75801da177e4SLinus Torvalds 75811da177e4SLinus Torvalds /* 75821da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 75832a4317c5SJeff Layton struct nfs4_client_reclaim * 75846b189105SScott Mayhew nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) 75851da177e4SLinus Torvalds { 75861da177e4SLinus Torvalds unsigned int strhashval; 75871da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 75881da177e4SLinus Torvalds 75896b189105SScott Mayhew strhashval = clientstr_hashval(name); 759052e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 75916b189105SScott Mayhew if (compare_blob(&crp->cr_name, &name) == 0) { 75921da177e4SLinus Torvalds return crp; 75931da177e4SLinus Torvalds } 75941da177e4SLinus Torvalds } 75951da177e4SLinus Torvalds return NULL; 75961da177e4SLinus Torvalds } 75971da177e4SLinus Torvalds 7598b37ad28bSAl Viro __be32 75991722b046SJ. Bruce Fields nfs4_check_open_reclaim(struct nfs4_client *clp) 76001da177e4SLinus Torvalds { 76011722b046SJ. Bruce Fields if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) 76023b3e7b72SJeff Layton return nfserr_no_grace; 76033b3e7b72SJeff Layton 76041722b046SJ. Bruce Fields if (nfsd4_client_record_check(clp)) 76050fe492dbSTrond Myklebust return nfserr_reclaim_bad; 76060fe492dbSTrond Myklebust 76070fe492dbSTrond Myklebust return nfs_ok; 76081da177e4SLinus Torvalds } 76091da177e4SLinus Torvalds 7610c2f1a551SMeelap Shah /* 7611c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 7612c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 7613c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 7614c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 7615c2f1a551SMeelap Shah * 7616c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 7617c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 7618c2f1a551SMeelap Shah */ 7619c2f1a551SMeelap Shah static void 7620c2f1a551SMeelap Shah set_max_delegations(void) 7621c2f1a551SMeelap Shah { 7622c2f1a551SMeelap Shah /* 7623c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 7624c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 7625c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 7626c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 7627c2f1a551SMeelap Shah */ 7628c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 7629c2f1a551SMeelap Shah } 7630c2f1a551SMeelap Shah 7631d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 76328daae4dcSStanislav Kinsbursky { 76338daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 76348daae4dcSStanislav Kinsbursky int i; 76358daae4dcSStanislav Kinsbursky 76366da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 76376da2ec56SKees Cook sizeof(struct list_head), 76386da2ec56SKees Cook GFP_KERNEL); 76398daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 7640382a62e7SStanislav Kinsbursky goto err; 76416da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 76426da2ec56SKees Cook sizeof(struct list_head), 76436da2ec56SKees Cook GFP_KERNEL); 76440a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 76450a7ec377SStanislav Kinsbursky goto err_unconf_id; 76466da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 76476da2ec56SKees Cook sizeof(struct list_head), 76486da2ec56SKees Cook GFP_KERNEL); 76491872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 76501872de0eSStanislav Kinsbursky goto err_sessionid; 76518daae4dcSStanislav Kinsbursky 7652382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 76538daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 76540a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 7655382a62e7SStanislav Kinsbursky } 76561872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 76571872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 7658382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 7659a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 76609cc76801SArnd Bergmann nn->boot_time = ktime_get_real_seconds(); 766181833de1SVasily Averin nn->grace_ended = false; 766281833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 766381833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 76645ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 766573758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 7666e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 7667c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 7668e0639dc5SOlga Kornievskaia spin_lock_init(&nn->s2s_cp_lock); 7669e0639dc5SOlga Kornievskaia idr_init(&nn->s2s_cp_stateids); 76708daae4dcSStanislav Kinsbursky 76710cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 76720cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 76730cc11a61SJeff Layton 767409121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 7675d85ed443SStanislav Kinsbursky get_net(net); 767609121281SStanislav Kinsbursky 76778daae4dcSStanislav Kinsbursky return 0; 7678382a62e7SStanislav Kinsbursky 76791872de0eSStanislav Kinsbursky err_sessionid: 76809b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 76810a7ec377SStanislav Kinsbursky err_unconf_id: 76820a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 7683382a62e7SStanislav Kinsbursky err: 7684382a62e7SStanislav Kinsbursky return -ENOMEM; 76858daae4dcSStanislav Kinsbursky } 76868daae4dcSStanislav Kinsbursky 76878daae4dcSStanislav Kinsbursky static void 76884dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 76898daae4dcSStanislav Kinsbursky { 76908daae4dcSStanislav Kinsbursky int i; 76918daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 76928daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 76938daae4dcSStanislav Kinsbursky 76948daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 76958daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 76968daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 76978daae4dcSStanislav Kinsbursky destroy_client(clp); 76988daae4dcSStanislav Kinsbursky } 76998daae4dcSStanislav Kinsbursky } 7700a99454aaSStanislav Kinsbursky 770168ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 770268ef3bc3SJeff Layton 77032b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 77042b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 77052b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 7706a99454aaSStanislav Kinsbursky destroy_client(clp); 7707a99454aaSStanislav Kinsbursky } 77082b905635SKinglong Mee } 7709a99454aaSStanislav Kinsbursky 77101872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 77110a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 77128daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 77134dce0ac9SStanislav Kinsbursky put_net(net); 77148daae4dcSStanislav Kinsbursky } 77158daae4dcSStanislav Kinsbursky 7716f252bc68SStanislav Kinsbursky int 7717d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 7718ac4d8ff2SNeilBrown { 77195e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 7720b5a1a81eSJ. Bruce Fields int ret; 7721b5a1a81eSJ. Bruce Fields 7722c6c7f2a8STrond Myklebust ret = nfs4_state_create_net(net); 77238daae4dcSStanislav Kinsbursky if (ret) 77248daae4dcSStanislav Kinsbursky return ret; 7725d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 7726d4318acdSJeff Layton nfsd4_client_tracking_init(net); 7727362063a5SScott Mayhew if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) 7728362063a5SScott Mayhew goto skip_grace; 772920b7d86fSArnd Bergmann printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", 77307e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 7731dd5e3fbcSChuck Lever trace_nfsd_grace_start(nn); 77325284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 7733d85ed443SStanislav Kinsbursky return 0; 7734362063a5SScott Mayhew 7735362063a5SScott Mayhew skip_grace: 7736362063a5SScott Mayhew printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n", 7737362063a5SScott Mayhew net->ns.inum); 7738362063a5SScott Mayhew queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ); 7739362063a5SScott Mayhew nfsd4_end_grace(nn); 7740362063a5SScott Mayhew return 0; 7741a6d6b781SJeff Layton } 7742d85ed443SStanislav Kinsbursky 7743d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 7744d85ed443SStanislav Kinsbursky 7745d85ed443SStanislav Kinsbursky int 7746d85ed443SStanislav Kinsbursky nfs4_state_start(void) 7747d85ed443SStanislav Kinsbursky { 7748d85ed443SStanislav Kinsbursky int ret; 7749d85ed443SStanislav Kinsbursky 775051a54568SJeff Layton laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 7751a6d6b781SJeff Layton if (laundry_wq == NULL) { 7752a6d6b781SJeff Layton ret = -ENOMEM; 7753a26dd64fSChuck Lever goto out; 7754a6d6b781SJeff Layton } 7755b5a1a81eSJ. Bruce Fields ret = nfsd4_create_callback_queue(); 7756b5a1a81eSJ. Bruce Fields if (ret) 7757b5a1a81eSJ. Bruce Fields goto out_free_laundry; 775809121281SStanislav Kinsbursky 7759c2f1a551SMeelap Shah set_max_delegations(); 7760b5a1a81eSJ. Bruce Fields return 0; 7761d85ed443SStanislav Kinsbursky 7762b5a1a81eSJ. Bruce Fields out_free_laundry: 7763b5a1a81eSJ. Bruce Fields destroy_workqueue(laundry_wq); 7764a26dd64fSChuck Lever out: 7765b5a1a81eSJ. Bruce Fields return ret; 77661da177e4SLinus Torvalds } 77671da177e4SLinus Torvalds 7768f252bc68SStanislav Kinsbursky void 77694dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 77701da177e4SLinus Torvalds { 77711da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 77721da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 77734dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 77741da177e4SLinus Torvalds 77754dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 77764dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 7777ac55fdc4SJeff Layton 77781da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 7779cdc97505SBenny Halevy spin_lock(&state_lock); 7780e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 77811da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 77823fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 778342690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 77841da177e4SLinus Torvalds } 7785cdc97505SBenny Halevy spin_unlock(&state_lock); 77861da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 77871da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 778842690676SJeff Layton list_del_init(&dp->dl_recall_lru); 77890af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 77901da177e4SLinus Torvalds } 77911da177e4SLinus Torvalds 77923320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 77934dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 7794f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 7795f4e44b39SDai Ngo nfsd4_ssc_shutdown_umount(nn); 7796f4e44b39SDai Ngo #endif 77971da177e4SLinus Torvalds } 77981da177e4SLinus Torvalds 77991da177e4SLinus Torvalds void 78001da177e4SLinus Torvalds nfs4_state_shutdown(void) 78011da177e4SLinus Torvalds { 78025e8d5c29SNeilBrown destroy_workqueue(laundry_wq); 7803c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 78041da177e4SLinus Torvalds } 78058b70484cSTigran Mkrtchyan 78068b70484cSTigran Mkrtchyan static void 78078b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 78088b70484cSTigran Mkrtchyan { 780951100d2bSOlga Kornievskaia if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) && 781051100d2bSOlga Kornievskaia CURRENT_STATEID(stateid)) 781137c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 78128b70484cSTigran Mkrtchyan } 78138b70484cSTigran Mkrtchyan 78148b70484cSTigran Mkrtchyan static void 78158b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 78168b70484cSTigran Mkrtchyan { 781737c593c5STigran Mkrtchyan if (cstate->minorversion) { 781837c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 781951100d2bSOlga Kornievskaia SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 782037c593c5STigran Mkrtchyan } 782137c593c5STigran Mkrtchyan } 782237c593c5STigran Mkrtchyan 782337c593c5STigran Mkrtchyan void 782437c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 782537c593c5STigran Mkrtchyan { 782651100d2bSOlga Kornievskaia CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 78278b70484cSTigran Mkrtchyan } 78288b70484cSTigran Mkrtchyan 782962cd4a59STigran Mkrtchyan /* 783062cd4a59STigran Mkrtchyan * functions to set current state id 783162cd4a59STigran Mkrtchyan */ 78328b70484cSTigran Mkrtchyan void 7833b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 7834b60e9859SChristoph Hellwig union nfsd4_op_u *u) 78359428fe1aSTigran Mkrtchyan { 7836b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 78379428fe1aSTigran Mkrtchyan } 78389428fe1aSTigran Mkrtchyan 78399428fe1aSTigran Mkrtchyan void 7840b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 7841b60e9859SChristoph Hellwig union nfsd4_op_u *u) 78428b70484cSTigran Mkrtchyan { 7843b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 78448b70484cSTigran Mkrtchyan } 78458b70484cSTigran Mkrtchyan 78468b70484cSTigran Mkrtchyan void 7847b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 7848b60e9859SChristoph Hellwig union nfsd4_op_u *u) 784962cd4a59STigran Mkrtchyan { 7850b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 785162cd4a59STigran Mkrtchyan } 785262cd4a59STigran Mkrtchyan 785362cd4a59STigran Mkrtchyan void 7854b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 7855b60e9859SChristoph Hellwig union nfsd4_op_u *u) 785662cd4a59STigran Mkrtchyan { 7857b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 785862cd4a59STigran Mkrtchyan } 785962cd4a59STigran Mkrtchyan 786062cd4a59STigran Mkrtchyan /* 786162cd4a59STigran Mkrtchyan * functions to consume current state id 786262cd4a59STigran Mkrtchyan */ 78631e97b519STigran Mkrtchyan 78641e97b519STigran Mkrtchyan void 786557832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 786657832e7bSChristoph Hellwig union nfsd4_op_u *u) 78679428fe1aSTigran Mkrtchyan { 786857832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 78699428fe1aSTigran Mkrtchyan } 78709428fe1aSTigran Mkrtchyan 78719428fe1aSTigran Mkrtchyan void 787257832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 787357832e7bSChristoph Hellwig union nfsd4_op_u *u) 78749428fe1aSTigran Mkrtchyan { 787557832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 78769428fe1aSTigran Mkrtchyan } 78779428fe1aSTigran Mkrtchyan 78789428fe1aSTigran Mkrtchyan void 787957832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 788057832e7bSChristoph Hellwig union nfsd4_op_u *u) 78811e97b519STigran Mkrtchyan { 788257832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 78831e97b519STigran Mkrtchyan } 78841e97b519STigran Mkrtchyan 78851e97b519STigran Mkrtchyan void 788657832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 788757832e7bSChristoph Hellwig union nfsd4_op_u *u) 78881e97b519STigran Mkrtchyan { 788957832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 78901e97b519STigran Mkrtchyan } 78911e97b519STigran Mkrtchyan 789262cd4a59STigran Mkrtchyan void 789357832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 789457832e7bSChristoph Hellwig union nfsd4_op_u *u) 78958b70484cSTigran Mkrtchyan { 789657832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 78978b70484cSTigran Mkrtchyan } 78988b70484cSTigran Mkrtchyan 78998b70484cSTigran Mkrtchyan void 790057832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 790157832e7bSChristoph Hellwig union nfsd4_op_u *u) 79028b70484cSTigran Mkrtchyan { 790357832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 79048b70484cSTigran Mkrtchyan } 790530813e27STigran Mkrtchyan 790630813e27STigran Mkrtchyan void 790757832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 790857832e7bSChristoph Hellwig union nfsd4_op_u *u) 790930813e27STigran Mkrtchyan { 791057832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 791130813e27STigran Mkrtchyan } 791230813e27STigran Mkrtchyan 791330813e27STigran Mkrtchyan void 791457832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 791557832e7bSChristoph Hellwig union nfsd4_op_u *u) 791630813e27STigran Mkrtchyan { 791757832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 791830813e27STigran Mkrtchyan } 7919