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> 47d47b295eSChuck Lever #include <linux/rhashtable.h> 48f4e44b39SDai Ngo #include <linux/nfs_ssc.h> 49d47b295eSChuck Lever 509a74af21SBoaz Harrosh #include "xdr4.h" 5106b332a5SJ. Bruce Fields #include "xdr4cb.h" 520a3adadeSJ. Bruce Fields #include "vfs.h" 53bfa4b365SJ. Bruce Fields #include "current_stateid.h" 541da177e4SLinus Torvalds 555e1533c7SStanislav Kinsbursky #include "netns.h" 569cf514ccSChristoph Hellwig #include "pnfs.h" 57fd4f83fdSJeff Layton #include "filecache.h" 58dd5e3fbcSChuck Lever #include "trace.h" 595e1533c7SStanislav Kinsbursky 601da177e4SLinus Torvalds #define NFSDDBG_FACILITY NFSDDBG_PROC 611da177e4SLinus Torvalds 62f32f3c2dSJ. Bruce Fields #define all_ones {{~0,~0},~0} 63f32f3c2dSJ. Bruce Fields static const stateid_t one_stateid = { 64f32f3c2dSJ. Bruce Fields .si_generation = ~0, 65f32f3c2dSJ. Bruce Fields .si_opaque = all_ones, 66f32f3c2dSJ. Bruce Fields }; 67f32f3c2dSJ. Bruce Fields static const stateid_t zero_stateid = { 68f32f3c2dSJ. Bruce Fields /* all fields zero */ 69f32f3c2dSJ. Bruce Fields }; 7019ff0f28STigran Mkrtchyan static const stateid_t currentstateid = { 7119ff0f28STigran Mkrtchyan .si_generation = 1, 7219ff0f28STigran Mkrtchyan }; 73fb500a7cSTrond Myklebust static const stateid_t close_stateid = { 74fb500a7cSTrond Myklebust .si_generation = 0xffffffffU, 75fb500a7cSTrond Myklebust }; 76f32f3c2dSJ. Bruce Fields 77ec6b5d7bSAndy Adamson static u64 current_sessionid = 1; 78fd39ca9aSNeilBrown 79f32f3c2dSJ. Bruce Fields #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 80f32f3c2dSJ. Bruce Fields #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 8119ff0f28STigran Mkrtchyan #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) 82ae254dacSAndrew Elble #define CLOSE_STATEID(stateid) (!memcmp((stateid), &close_stateid, sizeof(stateid_t))) 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* forward declarations */ 85f9c00c3aSJeff Layton static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner); 866011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid); 87362063a5SScott Mayhew void nfsd4_end_grace(struct nfsd_net *nn); 88624322f1SOlga Kornievskaia static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); 893341678fSChuck Lever static void nfsd4_file_hash_remove(struct nfs4_file *fi); 901da177e4SLinus Torvalds 918b671b80SJ. Bruce Fields /* Locking: */ 928b671b80SJ. Bruce Fields 938b671b80SJ. Bruce Fields /* 948b671b80SJ. Bruce Fields * Currently used for the del_recall_lru and file hash table. In an 958b671b80SJ. Bruce Fields * effort to decrease the scope of the client_mutex, this spinlock may 968b671b80SJ. Bruce Fields * eventually cover more: 978b671b80SJ. Bruce Fields */ 98cdc97505SBenny Halevy static DEFINE_SPINLOCK(state_lock); 998b671b80SJ. Bruce Fields 1004f34bd05SAndrew Elble enum nfsd4_st_mutex_lock_subclass { 1014f34bd05SAndrew Elble OPEN_STATEID_MUTEX = 0, 1024f34bd05SAndrew Elble LOCK_STATEID_MUTEX = 1, 1034f34bd05SAndrew Elble }; 1044f34bd05SAndrew Elble 105b401be22SJeff Layton /* 106b401be22SJeff Layton * A waitqueue for all in-progress 4.0 CLOSE operations that are waiting for 107b401be22SJeff Layton * the refcount on the open stateid to drop. 108b401be22SJeff Layton */ 109b401be22SJeff Layton static DECLARE_WAIT_QUEUE_HEAD(close_wq); 110b401be22SJeff Layton 11189c905beSJ. Bruce Fields /* 11289c905beSJ. Bruce Fields * A waitqueue where a writer to clients/#/ctl destroying a client can 11389c905beSJ. Bruce Fields * wait for cl_rpc_users to drop to 0 and then for the client to be 11489c905beSJ. Bruce Fields * unhashed. 11589c905beSJ. Bruce Fields */ 11689c905beSJ. Bruce Fields static DECLARE_WAIT_QUEUE_HEAD(expiry_wq); 11789c905beSJ. Bruce Fields 1189258a2d5SJeff Layton static struct kmem_cache *client_slab; 119abf1135bSChristoph Hellwig static struct kmem_cache *openowner_slab; 120abf1135bSChristoph Hellwig static struct kmem_cache *lockowner_slab; 121abf1135bSChristoph Hellwig static struct kmem_cache *file_slab; 122abf1135bSChristoph Hellwig static struct kmem_cache *stateid_slab; 123abf1135bSChristoph Hellwig static struct kmem_cache *deleg_slab; 1248287f009SSachin Bhamare static struct kmem_cache *odstate_slab; 125e60d4398SNeilBrown 12666b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *); 127508dc6e1SBenny Halevy 128c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; 12976d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; 1300162ac2bSChristoph Hellwig 13166af2579SDai Ngo static struct workqueue_struct *laundry_wq; 13266af2579SDai Ngo 133d76cc46bSDai Ngo int nfsd4_create_laundry_wq(void) 134d76cc46bSDai Ngo { 135d76cc46bSDai Ngo int rc = 0; 136d76cc46bSDai Ngo 137d76cc46bSDai Ngo laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); 138d76cc46bSDai Ngo if (laundry_wq == NULL) 139d76cc46bSDai Ngo rc = -ENOMEM; 140d76cc46bSDai Ngo return rc; 141d76cc46bSDai Ngo } 142d76cc46bSDai Ngo 143d76cc46bSDai Ngo void nfsd4_destroy_laundry_wq(void) 144d76cc46bSDai Ngo { 145d76cc46bSDai Ngo destroy_workqueue(laundry_wq); 146d76cc46bSDai Ngo } 147d76cc46bSDai Ngo 14866b2b9b2SJ. Bruce Fields static bool is_session_dead(struct nfsd4_session *ses) 149508dc6e1SBenny Halevy { 15066b2b9b2SJ. Bruce Fields return ses->se_flags & NFS4_SESSION_DEAD; 15166b2b9b2SJ. Bruce Fields } 15266b2b9b2SJ. Bruce Fields 153f0f51f5cSJ. Bruce Fields static __be32 mark_session_dead_locked(struct nfsd4_session *ses, int ref_held_by_me) 154f0f51f5cSJ. Bruce Fields { 155f0f51f5cSJ. Bruce Fields if (atomic_read(&ses->se_ref) > ref_held_by_me) 15666b2b9b2SJ. Bruce Fields return nfserr_jukebox; 15766b2b9b2SJ. Bruce Fields ses->se_flags |= NFS4_SESSION_DEAD; 15866b2b9b2SJ. Bruce Fields return nfs_ok; 15966b2b9b2SJ. Bruce Fields } 16066b2b9b2SJ. Bruce Fields 161221a6876SJ. Bruce Fields static bool is_client_expired(struct nfs4_client *clp) 162221a6876SJ. Bruce Fields { 163221a6876SJ. Bruce Fields return clp->cl_time == 0; 164221a6876SJ. Bruce Fields } 165221a6876SJ. Bruce Fields 1663a4ea23dSDai Ngo static void nfsd4_dec_courtesy_client_count(struct nfsd_net *nn, 1673a4ea23dSDai Ngo struct nfs4_client *clp) 1683a4ea23dSDai Ngo { 1693a4ea23dSDai Ngo if (clp->cl_state != NFSD4_ACTIVE) 1703a4ea23dSDai Ngo atomic_add_unless(&nn->nfsd_courtesy_clients, -1, 0); 1713a4ea23dSDai Ngo } 1723a4ea23dSDai Ngo 173221a6876SJ. Bruce Fields static __be32 get_client_locked(struct nfs4_client *clp) 174221a6876SJ. Bruce Fields { 1750a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1760a880a28STrond Myklebust 1770a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 1780a880a28STrond Myklebust 179221a6876SJ. Bruce Fields if (is_client_expired(clp)) 180221a6876SJ. Bruce Fields return nfserr_expired; 18114ed14ccSJ. Bruce Fields atomic_inc(&clp->cl_rpc_users); 1823a4ea23dSDai Ngo nfsd4_dec_courtesy_client_count(nn, clp); 18366af2579SDai Ngo clp->cl_state = NFSD4_ACTIVE; 184221a6876SJ. Bruce Fields return nfs_ok; 185221a6876SJ. Bruce Fields } 186221a6876SJ. Bruce Fields 187221a6876SJ. Bruce Fields /* must be called under the client_lock */ 188221a6876SJ. Bruce Fields static inline void 189221a6876SJ. Bruce Fields renew_client_locked(struct nfs4_client *clp) 190221a6876SJ. Bruce Fields { 191221a6876SJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 192221a6876SJ. Bruce Fields 193221a6876SJ. Bruce Fields if (is_client_expired(clp)) { 194221a6876SJ. Bruce Fields WARN_ON(1); 195221a6876SJ. Bruce Fields printk("%s: client (clientid %08x/%08x) already expired\n", 196221a6876SJ. Bruce Fields __func__, 197221a6876SJ. Bruce Fields clp->cl_clientid.cl_boot, 198221a6876SJ. Bruce Fields clp->cl_clientid.cl_id); 199221a6876SJ. Bruce Fields return; 200221a6876SJ. Bruce Fields } 201221a6876SJ. Bruce Fields 202221a6876SJ. Bruce Fields list_move_tail(&clp->cl_lru, &nn->client_lru); 20320b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 2043a4ea23dSDai Ngo nfsd4_dec_courtesy_client_count(nn, clp); 20566af2579SDai Ngo clp->cl_state = NFSD4_ACTIVE; 206221a6876SJ. Bruce Fields } 207221a6876SJ. Bruce Fields 208ba138435SFengguang Wu static void put_client_renew_locked(struct nfs4_client *clp) 209221a6876SJ. Bruce Fields { 2100a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2110a880a28STrond Myklebust 2120a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 2130a880a28STrond Myklebust 21414ed14ccSJ. Bruce Fields if (!atomic_dec_and_test(&clp->cl_rpc_users)) 215221a6876SJ. Bruce Fields return; 216221a6876SJ. Bruce Fields if (!is_client_expired(clp)) 217221a6876SJ. Bruce Fields renew_client_locked(clp); 21889c905beSJ. Bruce Fields else 21989c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 220221a6876SJ. Bruce Fields } 221221a6876SJ. Bruce Fields 2224b24ca7dSJeff Layton static void put_client_renew(struct nfs4_client *clp) 2234b24ca7dSJeff Layton { 2244b24ca7dSJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2254b24ca7dSJeff Layton 22614ed14ccSJ. Bruce Fields if (!atomic_dec_and_lock(&clp->cl_rpc_users, &nn->client_lock)) 227d6c249b4SJeff Layton return; 228d6c249b4SJeff Layton if (!is_client_expired(clp)) 229d6c249b4SJeff Layton renew_client_locked(clp); 23089c905beSJ. Bruce Fields else 23189c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 2324b24ca7dSJeff Layton spin_unlock(&nn->client_lock); 2334b24ca7dSJeff Layton } 2344b24ca7dSJeff Layton 235d4e19e70STrond Myklebust static __be32 nfsd4_get_session_locked(struct nfsd4_session *ses) 236d4e19e70STrond Myklebust { 237d4e19e70STrond Myklebust __be32 status; 238d4e19e70STrond Myklebust 239d4e19e70STrond Myklebust if (is_session_dead(ses)) 240d4e19e70STrond Myklebust return nfserr_badsession; 241d4e19e70STrond Myklebust status = get_client_locked(ses->se_client); 242d4e19e70STrond Myklebust if (status) 243d4e19e70STrond Myklebust return status; 244d4e19e70STrond Myklebust atomic_inc(&ses->se_ref); 245d4e19e70STrond Myklebust return nfs_ok; 246d4e19e70STrond Myklebust } 247d4e19e70STrond Myklebust 248d4e19e70STrond Myklebust static void nfsd4_put_session_locked(struct nfsd4_session *ses) 249d4e19e70STrond Myklebust { 250d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 2510a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2520a880a28STrond Myklebust 2530a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 254d4e19e70STrond Myklebust 255d4e19e70STrond Myklebust if (atomic_dec_and_test(&ses->se_ref) && is_session_dead(ses)) 256d4e19e70STrond Myklebust free_session(ses); 257d4e19e70STrond Myklebust put_client_renew_locked(clp); 258d4e19e70STrond Myklebust } 259d4e19e70STrond Myklebust 260d4e19e70STrond Myklebust static void nfsd4_put_session(struct nfsd4_session *ses) 261d4e19e70STrond Myklebust { 262d4e19e70STrond Myklebust struct nfs4_client *clp = ses->se_client; 263d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 264d4e19e70STrond Myklebust 265d4e19e70STrond Myklebust spin_lock(&nn->client_lock); 266d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 267d4e19e70STrond Myklebust spin_unlock(&nn->client_lock); 268d4e19e70STrond Myklebust } 269d4e19e70STrond Myklebust 27076d348faSJeff Layton static struct nfsd4_blocked_lock * 27176d348faSJeff Layton find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 27276d348faSJeff Layton struct nfsd_net *nn) 27376d348faSJeff Layton { 27476d348faSJeff Layton struct nfsd4_blocked_lock *cur, *found = NULL; 27576d348faSJeff Layton 2760cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 27776d348faSJeff Layton list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { 27876d348faSJeff Layton if (fh_match(fh, &cur->nbl_fh)) { 27976d348faSJeff Layton list_del_init(&cur->nbl_list); 28047446d74SVasily Averin WARN_ON(list_empty(&cur->nbl_lru)); 2817919d0a2SJeff Layton list_del_init(&cur->nbl_lru); 28276d348faSJeff Layton found = cur; 28376d348faSJeff Layton break; 28476d348faSJeff Layton } 28576d348faSJeff Layton } 2860cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 28776d348faSJeff Layton if (found) 288cb03f94fSNeilBrown locks_delete_block(&found->nbl_lock); 28976d348faSJeff Layton return found; 29076d348faSJeff Layton } 29176d348faSJeff Layton 29276d348faSJeff Layton static struct nfsd4_blocked_lock * 29376d348faSJeff Layton find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, 29476d348faSJeff Layton struct nfsd_net *nn) 29576d348faSJeff Layton { 29676d348faSJeff Layton struct nfsd4_blocked_lock *nbl; 29776d348faSJeff Layton 29876d348faSJeff Layton nbl = find_blocked_lock(lo, fh, nn); 29976d348faSJeff Layton if (!nbl) { 30076d348faSJeff Layton nbl= kmalloc(sizeof(*nbl), GFP_KERNEL); 30176d348faSJeff Layton if (nbl) { 302e1e8399eSVasily Averin INIT_LIST_HEAD(&nbl->nbl_list); 303e1e8399eSVasily Averin INIT_LIST_HEAD(&nbl->nbl_lru); 30476d348faSJeff Layton fh_copy_shallow(&nbl->nbl_fh, fh); 30576d348faSJeff Layton locks_init_lock(&nbl->nbl_lock); 30647446d74SVasily Averin kref_init(&nbl->nbl_kref); 30776d348faSJeff Layton nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client, 30876d348faSJeff Layton &nfsd4_cb_notify_lock_ops, 30976d348faSJeff Layton NFSPROC4_CLNT_CB_NOTIFY_LOCK); 31076d348faSJeff Layton } 31176d348faSJeff Layton } 31276d348faSJeff Layton return nbl; 31376d348faSJeff Layton } 31476d348faSJeff Layton 31576d348faSJeff Layton static void 31647446d74SVasily Averin free_nbl(struct kref *kref) 31747446d74SVasily Averin { 31847446d74SVasily Averin struct nfsd4_blocked_lock *nbl; 31947446d74SVasily Averin 32047446d74SVasily Averin nbl = container_of(kref, struct nfsd4_blocked_lock, nbl_kref); 32147446d74SVasily Averin kfree(nbl); 32247446d74SVasily Averin } 32347446d74SVasily Averin 32447446d74SVasily Averin static void 32576d348faSJeff Layton free_blocked_lock(struct nfsd4_blocked_lock *nbl) 32676d348faSJeff Layton { 3276aaafc43SJeff Layton locks_delete_block(&nbl->nbl_lock); 32876d348faSJeff Layton locks_release_private(&nbl->nbl_lock); 32947446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 33076d348faSJeff Layton } 33176d348faSJeff Layton 33268ef3bc3SJeff Layton static void 33368ef3bc3SJeff Layton remove_blocked_locks(struct nfs4_lockowner *lo) 33468ef3bc3SJeff Layton { 33568ef3bc3SJeff Layton struct nfs4_client *clp = lo->lo_owner.so_client; 33668ef3bc3SJeff Layton struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 33768ef3bc3SJeff Layton struct nfsd4_blocked_lock *nbl; 33868ef3bc3SJeff Layton LIST_HEAD(reaplist); 33968ef3bc3SJeff Layton 34068ef3bc3SJeff Layton /* Dequeue all blocked locks */ 34168ef3bc3SJeff Layton spin_lock(&nn->blocked_locks_lock); 34268ef3bc3SJeff Layton while (!list_empty(&lo->lo_blocked)) { 34368ef3bc3SJeff Layton nbl = list_first_entry(&lo->lo_blocked, 34468ef3bc3SJeff Layton struct nfsd4_blocked_lock, 34568ef3bc3SJeff Layton nbl_list); 34668ef3bc3SJeff Layton list_del_init(&nbl->nbl_list); 34747446d74SVasily Averin WARN_ON(list_empty(&nbl->nbl_lru)); 34868ef3bc3SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 34968ef3bc3SJeff Layton } 35068ef3bc3SJeff Layton spin_unlock(&nn->blocked_locks_lock); 35168ef3bc3SJeff Layton 35268ef3bc3SJeff Layton /* Now free them */ 35368ef3bc3SJeff Layton while (!list_empty(&reaplist)) { 35468ef3bc3SJeff Layton nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, 35568ef3bc3SJeff Layton nbl_lru); 35668ef3bc3SJeff Layton list_del_init(&nbl->nbl_lru); 35768ef3bc3SJeff Layton free_blocked_lock(nbl); 35868ef3bc3SJeff Layton } 35968ef3bc3SJeff Layton } 36068ef3bc3SJeff Layton 361f456458eSJeff Layton static void 362f456458eSJeff Layton nfsd4_cb_notify_lock_prepare(struct nfsd4_callback *cb) 363f456458eSJeff Layton { 364f456458eSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(cb, 365f456458eSJeff Layton struct nfsd4_blocked_lock, nbl_cb); 366f456458eSJeff Layton locks_delete_block(&nbl->nbl_lock); 367f456458eSJeff Layton } 368f456458eSJeff Layton 36976d348faSJeff Layton static int 37076d348faSJeff Layton nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) 37176d348faSJeff Layton { 3721035d654SChuck Lever trace_nfsd_cb_notify_lock_done(&zero_stateid, task); 3731035d654SChuck Lever 37476d348faSJeff Layton /* 37576d348faSJeff Layton * Since this is just an optimization, we don't try very hard if it 37676d348faSJeff Layton * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and 37776d348faSJeff Layton * just quit trying on anything else. 37876d348faSJeff Layton */ 37976d348faSJeff Layton switch (task->tk_status) { 38076d348faSJeff Layton case -NFS4ERR_DELAY: 38176d348faSJeff Layton rpc_delay(task, 1 * HZ); 38276d348faSJeff Layton return 0; 38376d348faSJeff Layton default: 38476d348faSJeff Layton return 1; 38576d348faSJeff Layton } 38676d348faSJeff Layton } 38776d348faSJeff Layton 38876d348faSJeff Layton static void 38976d348faSJeff Layton nfsd4_cb_notify_lock_release(struct nfsd4_callback *cb) 39076d348faSJeff Layton { 39176d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(cb, 39276d348faSJeff Layton struct nfsd4_blocked_lock, nbl_cb); 39376d348faSJeff Layton 39476d348faSJeff Layton free_blocked_lock(nbl); 39576d348faSJeff Layton } 39676d348faSJeff Layton 39776d348faSJeff Layton static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { 398f456458eSJeff Layton .prepare = nfsd4_cb_notify_lock_prepare, 39976d348faSJeff Layton .done = nfsd4_cb_notify_lock_done, 40076d348faSJeff Layton .release = nfsd4_cb_notify_lock_release, 40176d348faSJeff Layton }; 40276d348faSJeff Layton 403ebd9d2c2SJ. Bruce Fields /* 404ebd9d2c2SJ. Bruce Fields * We store the NONE, READ, WRITE, and BOTH bits separately in the 405ebd9d2c2SJ. Bruce Fields * st_{access,deny}_bmap field of the stateid, in order to track not 406ebd9d2c2SJ. Bruce Fields * only what share bits are currently in force, but also what 407ebd9d2c2SJ. Bruce Fields * combinations of share bits previous opens have used. This allows us 4083dcd1d8aSJ. Bruce Fields * to enforce the recommendation in 4093dcd1d8aSJ. Bruce Fields * https://datatracker.ietf.org/doc/html/rfc7530#section-16.19.4 that 4103dcd1d8aSJ. Bruce Fields * the server return an error if the client attempt to downgrade to a 4113dcd1d8aSJ. Bruce Fields * combination of share bits not explicable by closing some of its 4123dcd1d8aSJ. Bruce Fields * previous opens. 413ebd9d2c2SJ. Bruce Fields * 4143dcd1d8aSJ. Bruce Fields * This enforcement is arguably incomplete, since we don't keep 415ebd9d2c2SJ. Bruce Fields * track of access/deny bit combinations; so, e.g., we allow: 416ebd9d2c2SJ. Bruce Fields * 417ebd9d2c2SJ. Bruce Fields * OPEN allow read, deny write 418ebd9d2c2SJ. Bruce Fields * OPEN allow both, deny none 419ebd9d2c2SJ. Bruce Fields * DOWNGRADE allow read, deny none 420ebd9d2c2SJ. Bruce Fields * 421ebd9d2c2SJ. Bruce Fields * which we should reject. 4223dcd1d8aSJ. Bruce Fields * 4233dcd1d8aSJ. Bruce Fields * But you could also argue that our current code is already overkill, 4243dcd1d8aSJ. Bruce Fields * since it only exists to return NFS4ERR_INVAL on incorrect client 4253dcd1d8aSJ. Bruce Fields * behavior. 426ebd9d2c2SJ. Bruce Fields */ 427ebd9d2c2SJ. Bruce Fields static unsigned int 428ebd9d2c2SJ. Bruce Fields bmap_to_share_mode(unsigned long bmap) 429ebd9d2c2SJ. Bruce Fields { 430ebd9d2c2SJ. Bruce Fields int i; 431ebd9d2c2SJ. Bruce Fields unsigned int access = 0; 432ebd9d2c2SJ. Bruce Fields 433ebd9d2c2SJ. Bruce Fields for (i = 1; i < 4; i++) { 434ebd9d2c2SJ. Bruce Fields if (test_bit(i, &bmap)) 435ebd9d2c2SJ. Bruce Fields access |= i; 436ebd9d2c2SJ. Bruce Fields } 437ebd9d2c2SJ. Bruce Fields return access; 438ebd9d2c2SJ. Bruce Fields } 439ebd9d2c2SJ. Bruce Fields 440ebd9d2c2SJ. Bruce Fields /* set share access for a given stateid */ 441ebd9d2c2SJ. Bruce Fields static inline void 442ebd9d2c2SJ. Bruce Fields set_access(u32 access, struct nfs4_ol_stateid *stp) 443ebd9d2c2SJ. Bruce Fields { 444ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << access; 445ebd9d2c2SJ. Bruce Fields 446ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 447ebd9d2c2SJ. Bruce Fields stp->st_access_bmap |= mask; 448ebd9d2c2SJ. Bruce Fields } 449ebd9d2c2SJ. Bruce Fields 450ebd9d2c2SJ. Bruce Fields /* clear share access for a given stateid */ 451ebd9d2c2SJ. Bruce Fields static inline void 452ebd9d2c2SJ. Bruce Fields clear_access(u32 access, struct nfs4_ol_stateid *stp) 453ebd9d2c2SJ. Bruce Fields { 454ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << access; 455ebd9d2c2SJ. Bruce Fields 456ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); 457ebd9d2c2SJ. Bruce Fields stp->st_access_bmap &= ~mask; 458ebd9d2c2SJ. Bruce Fields } 459ebd9d2c2SJ. Bruce Fields 460ebd9d2c2SJ. Bruce Fields /* test whether a given stateid has access */ 461ebd9d2c2SJ. Bruce Fields static inline bool 462ebd9d2c2SJ. Bruce Fields test_access(u32 access, struct nfs4_ol_stateid *stp) 463ebd9d2c2SJ. Bruce Fields { 464ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << access; 465ebd9d2c2SJ. Bruce Fields 466ebd9d2c2SJ. Bruce Fields return (bool)(stp->st_access_bmap & mask); 467ebd9d2c2SJ. Bruce Fields } 468ebd9d2c2SJ. Bruce Fields 469ebd9d2c2SJ. Bruce Fields /* set share deny for a given stateid */ 470ebd9d2c2SJ. Bruce Fields static inline void 471ebd9d2c2SJ. Bruce Fields set_deny(u32 deny, struct nfs4_ol_stateid *stp) 472ebd9d2c2SJ. Bruce Fields { 473ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << deny; 474ebd9d2c2SJ. Bruce Fields 475ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 476ebd9d2c2SJ. Bruce Fields stp->st_deny_bmap |= mask; 477ebd9d2c2SJ. Bruce Fields } 478ebd9d2c2SJ. Bruce Fields 479ebd9d2c2SJ. Bruce Fields /* clear share deny for a given stateid */ 480ebd9d2c2SJ. Bruce Fields static inline void 481ebd9d2c2SJ. Bruce Fields clear_deny(u32 deny, struct nfs4_ol_stateid *stp) 482ebd9d2c2SJ. Bruce Fields { 483ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << deny; 484ebd9d2c2SJ. Bruce Fields 485ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); 486ebd9d2c2SJ. Bruce Fields stp->st_deny_bmap &= ~mask; 487ebd9d2c2SJ. Bruce Fields } 488ebd9d2c2SJ. Bruce Fields 489ebd9d2c2SJ. Bruce Fields /* test whether a given stateid is denying specific access */ 490ebd9d2c2SJ. Bruce Fields static inline bool 491ebd9d2c2SJ. Bruce Fields test_deny(u32 deny, struct nfs4_ol_stateid *stp) 492ebd9d2c2SJ. Bruce Fields { 493ebd9d2c2SJ. Bruce Fields unsigned char mask = 1 << deny; 494ebd9d2c2SJ. Bruce Fields 495ebd9d2c2SJ. Bruce Fields return (bool)(stp->st_deny_bmap & mask); 496ebd9d2c2SJ. Bruce Fields } 497ebd9d2c2SJ. Bruce Fields 498ebd9d2c2SJ. Bruce Fields static int nfs4_access_to_omode(u32 access) 499ebd9d2c2SJ. Bruce Fields { 500ebd9d2c2SJ. Bruce Fields switch (access & NFS4_SHARE_ACCESS_BOTH) { 501ebd9d2c2SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 502ebd9d2c2SJ. Bruce Fields return O_RDONLY; 503ebd9d2c2SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 504ebd9d2c2SJ. Bruce Fields return O_WRONLY; 505ebd9d2c2SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 506ebd9d2c2SJ. Bruce Fields return O_RDWR; 507ebd9d2c2SJ. Bruce Fields } 508ebd9d2c2SJ. Bruce Fields WARN_ON_ONCE(1); 509ebd9d2c2SJ. Bruce Fields return O_RDONLY; 510ebd9d2c2SJ. Bruce Fields } 511ebd9d2c2SJ. Bruce Fields 512ebd9d2c2SJ. Bruce Fields static inline int 513ebd9d2c2SJ. Bruce Fields access_permit_read(struct nfs4_ol_stateid *stp) 514ebd9d2c2SJ. Bruce Fields { 515ebd9d2c2SJ. Bruce Fields return test_access(NFS4_SHARE_ACCESS_READ, stp) || 516ebd9d2c2SJ. Bruce Fields test_access(NFS4_SHARE_ACCESS_BOTH, stp) || 517ebd9d2c2SJ. Bruce Fields test_access(NFS4_SHARE_ACCESS_WRITE, stp); 518ebd9d2c2SJ. Bruce Fields } 519ebd9d2c2SJ. Bruce Fields 520ebd9d2c2SJ. Bruce Fields static inline int 521ebd9d2c2SJ. Bruce Fields access_permit_write(struct nfs4_ol_stateid *stp) 522ebd9d2c2SJ. Bruce Fields { 523ebd9d2c2SJ. Bruce Fields return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || 524ebd9d2c2SJ. Bruce Fields test_access(NFS4_SHARE_ACCESS_BOTH, stp); 525ebd9d2c2SJ. Bruce Fields } 526ebd9d2c2SJ. Bruce Fields 527b5971afaSKinglong Mee static inline struct nfs4_stateowner * 528b5971afaSKinglong Mee nfs4_get_stateowner(struct nfs4_stateowner *sop) 529b5971afaSKinglong Mee { 530b5971afaSKinglong Mee atomic_inc(&sop->so_count); 531b5971afaSKinglong Mee return sop; 532b5971afaSKinglong Mee } 533b5971afaSKinglong Mee 5347ffb5880STrond Myklebust static int 535d4f0489fSTrond Myklebust same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner) 5367ffb5880STrond Myklebust { 5377ffb5880STrond Myklebust return (sop->so_owner.len == owner->len) && 538d4f0489fSTrond Myklebust 0 == memcmp(sop->so_owner.data, owner->data, owner->len); 5397ffb5880STrond Myklebust } 5407ffb5880STrond Myklebust 5417ffb5880STrond Myklebust static struct nfs4_openowner * 5427ffb5880STrond Myklebust find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, 543d4f0489fSTrond Myklebust struct nfs4_client *clp) 5447ffb5880STrond Myklebust { 5457ffb5880STrond Myklebust struct nfs4_stateowner *so; 5467ffb5880STrond Myklebust 547d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 5487ffb5880STrond Myklebust 549d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[hashval], 550d4f0489fSTrond Myklebust so_strhash) { 5517ffb5880STrond Myklebust if (!so->so_is_open_owner) 5527ffb5880STrond Myklebust continue; 553b5971afaSKinglong Mee if (same_owner_str(so, &open->op_owner)) 554b5971afaSKinglong Mee return openowner(nfs4_get_stateowner(so)); 5557ffb5880STrond Myklebust } 5567ffb5880STrond Myklebust return NULL; 5577ffb5880STrond Myklebust } 5587ffb5880STrond Myklebust 5597ffb5880STrond Myklebust static struct nfs4_openowner * 5607ffb5880STrond Myklebust find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, 561d4f0489fSTrond Myklebust struct nfs4_client *clp) 5627ffb5880STrond Myklebust { 5637ffb5880STrond Myklebust struct nfs4_openowner *oo; 5647ffb5880STrond Myklebust 565d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 566d4f0489fSTrond Myklebust oo = find_openstateowner_str_locked(hashval, open, clp); 567d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 5687ffb5880STrond Myklebust return oo; 5697ffb5880STrond Myklebust } 5707ffb5880STrond Myklebust 5711da177e4SLinus Torvalds static inline u32 5721da177e4SLinus Torvalds opaque_hashval(const void *ptr, int nbytes) 5731da177e4SLinus Torvalds { 5741da177e4SLinus Torvalds unsigned char *cptr = (unsigned char *) ptr; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds u32 x = 0; 5771da177e4SLinus Torvalds while (nbytes--) { 5781da177e4SLinus Torvalds x *= 37; 5791da177e4SLinus Torvalds x += *cptr++; 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds return x; 5821da177e4SLinus Torvalds } 5831da177e4SLinus Torvalds 5845b095e99SJeff Layton static void nfsd4_free_file_rcu(struct rcu_head *rcu) 58532513b40SJ. Bruce Fields { 5865b095e99SJeff Layton struct nfs4_file *fp = container_of(rcu, struct nfs4_file, fi_rcu); 5875b095e99SJeff Layton 5885b095e99SJeff Layton kmem_cache_free(file_slab, fp); 58932513b40SJ. Bruce Fields } 59032513b40SJ. Bruce Fields 591e6ba76e1SChristoph Hellwig void 59213cd2184SNeilBrown put_nfs4_file(struct nfs4_file *fi) 59313cd2184SNeilBrown { 594d47b295eSChuck Lever if (refcount_dec_and_test(&fi->fi_ref)) { 5953341678fSChuck Lever nfsd4_file_hash_remove(fi); 5968287f009SSachin Bhamare WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); 5975b095e99SJeff Layton WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); 5985b095e99SJeff Layton call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); 5998b671b80SJ. Bruce Fields } 60013cd2184SNeilBrown } 60113cd2184SNeilBrown 602eb82dd39SJeff Layton static struct nfsd_file * 603de18643dSTrond Myklebust __nfs4_get_fd(struct nfs4_file *f, int oflag) 604de18643dSTrond Myklebust { 605de18643dSTrond Myklebust if (f->fi_fds[oflag]) 606eb82dd39SJeff Layton return nfsd_file_get(f->fi_fds[oflag]); 607de18643dSTrond Myklebust return NULL; 608de18643dSTrond Myklebust } 609de18643dSTrond Myklebust 610eb82dd39SJeff Layton static struct nfsd_file * 611de18643dSTrond Myklebust find_writeable_file_locked(struct nfs4_file *f) 612de18643dSTrond Myklebust { 613eb82dd39SJeff Layton struct nfsd_file *ret; 614de18643dSTrond Myklebust 615de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 616de18643dSTrond Myklebust 617de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 618de18643dSTrond Myklebust if (!ret) 619de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 620de18643dSTrond Myklebust return ret; 621de18643dSTrond Myklebust } 622de18643dSTrond Myklebust 623eb82dd39SJeff Layton static struct nfsd_file * 624de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 625de18643dSTrond Myklebust { 626eb82dd39SJeff Layton struct nfsd_file *ret; 627de18643dSTrond Myklebust 628de18643dSTrond Myklebust spin_lock(&f->fi_lock); 629de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 630de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 631de18643dSTrond Myklebust 632de18643dSTrond Myklebust return ret; 633de18643dSTrond Myklebust } 634de18643dSTrond Myklebust 635eb82dd39SJeff Layton static struct nfsd_file * 636eb82dd39SJeff Layton find_readable_file_locked(struct nfs4_file *f) 637de18643dSTrond Myklebust { 638eb82dd39SJeff Layton struct nfsd_file *ret; 639de18643dSTrond Myklebust 640de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 641de18643dSTrond Myklebust 642de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 643de18643dSTrond Myklebust if (!ret) 644de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 645de18643dSTrond Myklebust return ret; 646de18643dSTrond Myklebust } 647de18643dSTrond Myklebust 648eb82dd39SJeff Layton static struct nfsd_file * 649de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 650de18643dSTrond Myklebust { 651eb82dd39SJeff Layton struct nfsd_file *ret; 652de18643dSTrond Myklebust 653de18643dSTrond Myklebust spin_lock(&f->fi_lock); 654de18643dSTrond Myklebust ret = find_readable_file_locked(f); 655de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 656de18643dSTrond Myklebust 657de18643dSTrond Myklebust return ret; 658de18643dSTrond Myklebust } 659de18643dSTrond Myklebust 660eb82dd39SJeff Layton struct nfsd_file * 661de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 662de18643dSTrond Myklebust { 663eb82dd39SJeff Layton struct nfsd_file *ret; 664de18643dSTrond Myklebust 665a451b123STrond Myklebust if (!f) 666a451b123STrond Myklebust return NULL; 667de18643dSTrond Myklebust spin_lock(&f->fi_lock); 668de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDWR); 669de18643dSTrond Myklebust if (!ret) { 670de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_WRONLY); 671de18643dSTrond Myklebust if (!ret) 672de18643dSTrond Myklebust ret = __nfs4_get_fd(f, O_RDONLY); 673de18643dSTrond Myklebust } 674de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 675de18643dSTrond Myklebust return ret; 676de18643dSTrond Myklebust } 677de18643dSTrond Myklebust 678e0aa6510SJeff Layton static struct nfsd_file *find_any_file_locked(struct nfs4_file *f) 6799affa435SJ. Bruce Fields { 680e0aa6510SJeff Layton lockdep_assert_held(&f->fi_lock); 6819affa435SJ. Bruce Fields 682e0aa6510SJeff Layton if (f->fi_fds[O_RDWR]) 683e0aa6510SJeff Layton return f->fi_fds[O_RDWR]; 684e0aa6510SJeff Layton if (f->fi_fds[O_WRONLY]) 685e0aa6510SJeff Layton return f->fi_fds[O_WRONLY]; 686e0aa6510SJeff Layton if (f->fi_fds[O_RDONLY]) 687e0aa6510SJeff Layton return f->fi_fds[O_RDONLY]; 688e0aa6510SJeff Layton return NULL; 689e0aa6510SJeff Layton } 690e0aa6510SJeff Layton 691e0aa6510SJeff Layton static struct nfsd_file *find_deleg_file_locked(struct nfs4_file *f) 692e0aa6510SJeff Layton { 693e0aa6510SJeff Layton lockdep_assert_held(&f->fi_lock); 694e0aa6510SJeff Layton 6959affa435SJ. Bruce Fields if (f->fi_deleg_file) 696e0aa6510SJeff Layton return f->fi_deleg_file; 697e0aa6510SJeff Layton return NULL; 6989affa435SJ. Bruce Fields } 6999affa435SJ. Bruce Fields 70002a3508dSTrond Myklebust static atomic_long_t num_delegations; 701697ce9beSZhang Yanfei unsigned long max_delegations; 702ef0f3390SNeilBrown 703ef0f3390SNeilBrown /* 704ef0f3390SNeilBrown * Open owner state (share locks) 705ef0f3390SNeilBrown */ 706ef0f3390SNeilBrown 70716bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 70816bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 70916bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 71016bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 711ef0f3390SNeilBrown 712d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 713ddc04c41SJ. Bruce Fields { 714ddc04c41SJ. Bruce Fields unsigned int ret; 715ddc04c41SJ. Bruce Fields 716ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 71716bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 718ddc04c41SJ. Bruce Fields } 719ef0f3390SNeilBrown 720d47b295eSChuck Lever static struct rhltable nfs4_file_rhltable ____cacheline_aligned_in_smp; 72135079582SShan Wei 722d47b295eSChuck Lever static const struct rhashtable_params nfs4_file_rhash_params = { 723d47b295eSChuck Lever .key_len = sizeof_field(struct nfs4_file, fi_inode), 724d47b295eSChuck Lever .key_offset = offsetof(struct nfs4_file, fi_inode), 725d47b295eSChuck Lever .head_offset = offsetof(struct nfs4_file, fi_rlist), 726ca943217STrond Myklebust 727d47b295eSChuck Lever /* 728d47b295eSChuck Lever * Start with a single page hash table to reduce resizing churn 729d47b295eSChuck Lever * on light workloads. 730d47b295eSChuck Lever */ 731d47b295eSChuck Lever .min_size = 256, 732d47b295eSChuck Lever .automatic_shrinking = true, 733d47b295eSChuck Lever }; 734ef0f3390SNeilBrown 7353d694271SDai Ngo /* 7363d694271SDai Ngo * Check if courtesy clients have conflicting access and resolve it if possible 7373d694271SDai Ngo * 7383d694271SDai Ngo * access: is op_share_access if share_access is true. 7393d694271SDai Ngo * Check if access mode, op_share_access, would conflict with 7403d694271SDai Ngo * the current deny mode of the file 'fp'. 7413d694271SDai Ngo * access: is op_share_deny if share_access is false. 7423d694271SDai Ngo * Check if the deny mode, op_share_deny, would conflict with 7433d694271SDai Ngo * current access of the file 'fp'. 7443d694271SDai Ngo * stp: skip checking this entry. 7453d694271SDai Ngo * new_stp: normal open, not open upgrade. 7463d694271SDai Ngo * 7473d694271SDai Ngo * Function returns: 7483d694271SDai Ngo * false - access/deny mode conflict with normal client. 7493d694271SDai Ngo * true - no conflict or conflict with courtesy client(s) is resolved. 7503d694271SDai Ngo */ 7513d694271SDai Ngo static bool 7523d694271SDai Ngo nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp, 7533d694271SDai Ngo struct nfs4_ol_stateid *stp, u32 access, bool share_access) 7543d694271SDai Ngo { 7553d694271SDai Ngo struct nfs4_ol_stateid *st; 7563d694271SDai Ngo bool resolvable = true; 7573d694271SDai Ngo unsigned char bmap; 7583d694271SDai Ngo struct nfsd_net *nn; 7593d694271SDai Ngo struct nfs4_client *clp; 7603d694271SDai Ngo 7613d694271SDai Ngo lockdep_assert_held(&fp->fi_lock); 7623d694271SDai Ngo list_for_each_entry(st, &fp->fi_stateids, st_perfile) { 7633d694271SDai Ngo /* ignore lock stateid */ 7643d694271SDai Ngo if (st->st_openstp) 7653d694271SDai Ngo continue; 7663d694271SDai Ngo if (st == stp && new_stp) 7673d694271SDai Ngo continue; 7683d694271SDai Ngo /* check file access against deny mode or vice versa */ 7693d694271SDai Ngo bmap = share_access ? st->st_deny_bmap : st->st_access_bmap; 7703d694271SDai Ngo if (!(access & bmap_to_share_mode(bmap))) 7713d694271SDai Ngo continue; 7723d694271SDai Ngo clp = st->st_stid.sc_client; 7733d694271SDai Ngo if (try_to_expire_client(clp)) 7743d694271SDai Ngo continue; 7753d694271SDai Ngo resolvable = false; 7763d694271SDai Ngo break; 7773d694271SDai Ngo } 7783d694271SDai Ngo if (resolvable) { 7793d694271SDai Ngo clp = stp->st_stid.sc_client; 7803d694271SDai Ngo nn = net_generic(clp->net, nfsd_net_id); 7813d694271SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 7823d694271SDai Ngo } 7833d694271SDai Ngo return resolvable; 7843d694271SDai Ngo } 7853d694271SDai Ngo 78612659651SJeff Layton static void 78712659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 7883477565eSJ. Bruce Fields { 7897214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 7907214e860SJeff Layton 79112659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 79212659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 79312659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 79412659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 7953477565eSJ. Bruce Fields } 7963477565eSJ. Bruce Fields 79712659651SJeff Layton static __be32 79812659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 799998db52cSJ. Bruce Fields { 8007214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 8017214e860SJeff Layton 80212659651SJeff Layton /* Does this access mode make sense? */ 80312659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 80412659651SJeff Layton return nfserr_inval; 80512659651SJeff Layton 806baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 807baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 808baeb4ff0SJeff Layton return nfserr_share_denied; 809baeb4ff0SJeff Layton 81012659651SJeff Layton __nfs4_file_get_access(fp, access); 81112659651SJeff Layton return nfs_ok; 812998db52cSJ. Bruce Fields } 813998db52cSJ. Bruce Fields 814baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 815baeb4ff0SJeff Layton { 816baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 817baeb4ff0SJeff Layton if (deny) { 818baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 819baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 820baeb4ff0SJeff Layton return nfserr_inval; 821baeb4ff0SJeff Layton 822baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 823baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 824baeb4ff0SJeff Layton return nfserr_share_denied; 825baeb4ff0SJeff Layton 826baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 827baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 828baeb4ff0SJeff Layton return nfserr_share_denied; 829baeb4ff0SJeff Layton } 830baeb4ff0SJeff Layton return nfs_ok; 831baeb4ff0SJeff Layton } 832baeb4ff0SJeff Layton 833998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 834f9d7562fSJ. Bruce Fields { 835de18643dSTrond Myklebust might_lock(&fp->fi_lock); 836de18643dSTrond Myklebust 837de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 838fd4f83fdSJeff Layton struct nfsd_file *f1 = NULL; 839fd4f83fdSJeff Layton struct nfsd_file *f2 = NULL; 840de18643dSTrond Myklebust 8416d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 8420c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 8436d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 844de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 845de18643dSTrond Myklebust if (f1) 846dcf3f809SChuck Lever nfsd_file_put(f1); 847de18643dSTrond Myklebust if (f2) 848dcf3f809SChuck Lever nfsd_file_put(f2); 849f9d7562fSJ. Bruce Fields } 850f9d7562fSJ. Bruce Fields } 851f9d7562fSJ. Bruce Fields 85212659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 853998db52cSJ. Bruce Fields { 85412659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 85512659651SJeff Layton 85612659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 857998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 85812659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 85912659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 860998db52cSJ. Bruce Fields } 861998db52cSJ. Bruce Fields 8628287f009SSachin Bhamare /* 8638287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 8648287f009SSachin Bhamare * pNFS for proper return on close semantics. 8658287f009SSachin Bhamare * 8668287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 8678287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 8688287f009SSachin Bhamare */ 8698287f009SSachin Bhamare static struct nfs4_clnt_odstate * 8708287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 8718287f009SSachin Bhamare { 8728287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 8738287f009SSachin Bhamare 8748287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 8758287f009SSachin Bhamare if (co) { 8768287f009SSachin Bhamare co->co_client = clp; 877cff7cb2eSElena Reshetova refcount_set(&co->co_odcount, 1); 8788287f009SSachin Bhamare } 8798287f009SSachin Bhamare return co; 8808287f009SSachin Bhamare } 8818287f009SSachin Bhamare 8828287f009SSachin Bhamare static void 8838287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 8848287f009SSachin Bhamare { 8858287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 8868287f009SSachin Bhamare 8878287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 8888287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 8898287f009SSachin Bhamare } 8908287f009SSachin Bhamare 8918287f009SSachin Bhamare static inline void 8928287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 8938287f009SSachin Bhamare { 8948287f009SSachin Bhamare if (co) 895cff7cb2eSElena Reshetova refcount_inc(&co->co_odcount); 8968287f009SSachin Bhamare } 8978287f009SSachin Bhamare 8988287f009SSachin Bhamare static void 8998287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 9008287f009SSachin Bhamare { 9018287f009SSachin Bhamare struct nfs4_file *fp; 9028287f009SSachin Bhamare 9038287f009SSachin Bhamare if (!co) 9048287f009SSachin Bhamare return; 9058287f009SSachin Bhamare 9068287f009SSachin Bhamare fp = co->co_file; 907cff7cb2eSElena Reshetova if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 9088287f009SSachin Bhamare list_del(&co->co_perfile); 9098287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 9108287f009SSachin Bhamare 9118287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 9128287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 9138287f009SSachin Bhamare } 9148287f009SSachin Bhamare } 9158287f009SSachin Bhamare 9168287f009SSachin Bhamare static struct nfs4_clnt_odstate * 9178287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 9188287f009SSachin Bhamare { 9198287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 9208287f009SSachin Bhamare struct nfs4_client *cl; 9218287f009SSachin Bhamare 9228287f009SSachin Bhamare if (!new) 9238287f009SSachin Bhamare return NULL; 9248287f009SSachin Bhamare 9258287f009SSachin Bhamare cl = new->co_client; 9268287f009SSachin Bhamare 9278287f009SSachin Bhamare spin_lock(&fp->fi_lock); 9288287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 9298287f009SSachin Bhamare if (co->co_client == cl) { 9308287f009SSachin Bhamare get_clnt_odstate(co); 9318287f009SSachin Bhamare goto out; 9328287f009SSachin Bhamare } 9338287f009SSachin Bhamare } 9348287f009SSachin Bhamare co = new; 9358287f009SSachin Bhamare co->co_file = fp; 9368287f009SSachin Bhamare hash_clnt_odstate_locked(new); 9378287f009SSachin Bhamare out: 9388287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 9398287f009SSachin Bhamare return co; 9408287f009SSachin Bhamare } 9418287f009SSachin Bhamare 942d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 943d19fb70dSKinglong Mee void (*sc_free)(struct nfs4_stid *)) 944996e0938SJ. Bruce Fields { 9453abdb607SJ. Bruce Fields struct nfs4_stid *stid; 9463abdb607SJ. Bruce Fields int new_id; 9473abdb607SJ. Bruce Fields 948f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 9493abdb607SJ. Bruce Fields if (!stid) 9503abdb607SJ. Bruce Fields return NULL; 951996e0938SJ. Bruce Fields 9524770d722SJeff Layton idr_preload(GFP_KERNEL); 9534770d722SJeff Layton spin_lock(&cl->cl_lock); 95478599c42SJ. Bruce Fields /* Reserving 0 for start of file in nfsdfs "states" file: */ 95578599c42SJ. Bruce Fields new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 1, 0, GFP_NOWAIT); 9564770d722SJeff Layton spin_unlock(&cl->cl_lock); 9574770d722SJeff Layton idr_preload_end(); 958ebd6c707STejun Heo if (new_id < 0) 9593abdb607SJ. Bruce Fields goto out_free; 960d19fb70dSKinglong Mee 961d19fb70dSKinglong Mee stid->sc_free = sc_free; 9623abdb607SJ. Bruce Fields stid->sc_client = cl; 9633abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 9643abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 9653abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 966a15dfcd5SElena Reshetova refcount_set(&stid->sc_count, 1); 9679767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 968624322f1SOlga Kornievskaia INIT_LIST_HEAD(&stid->sc_cp_list); 9693abdb607SJ. Bruce Fields 970996e0938SJ. Bruce Fields /* 9713abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 9723abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 9733abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 9743abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 9753abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 9763abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 9773abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 978996e0938SJ. Bruce Fields */ 9793abdb607SJ. Bruce Fields return stid; 9803abdb607SJ. Bruce Fields out_free: 9812c44a234SWei Yongjun kmem_cache_free(slab, stid); 9823abdb607SJ. Bruce Fields return NULL; 9832a74aba7SJ. Bruce Fields } 9842a74aba7SJ. Bruce Fields 985e0639dc5SOlga Kornievskaia /* 986e0639dc5SOlga Kornievskaia * Create a unique stateid_t to represent each COPY. 987e0639dc5SOlga Kornievskaia */ 988624322f1SOlga Kornievskaia static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, 989781fde1aSChuck Lever unsigned char cs_type) 990e0639dc5SOlga Kornievskaia { 991e0639dc5SOlga Kornievskaia int new_id; 992e0639dc5SOlga Kornievskaia 993781fde1aSChuck Lever stid->cs_stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; 994781fde1aSChuck Lever stid->cs_stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; 995781fde1aSChuck Lever stid->cs_type = cs_type; 996624322f1SOlga Kornievskaia 997e0639dc5SOlga Kornievskaia idr_preload(GFP_KERNEL); 998e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 999624322f1SOlga Kornievskaia new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT); 1000781fde1aSChuck Lever stid->cs_stid.si_opaque.so_id = new_id; 1001781fde1aSChuck Lever stid->cs_stid.si_generation = 1; 1002e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1003e0639dc5SOlga Kornievskaia idr_preload_end(); 1004e0639dc5SOlga Kornievskaia if (new_id < 0) 1005e0639dc5SOlga Kornievskaia return 0; 1006e0639dc5SOlga Kornievskaia return 1; 1007e0639dc5SOlga Kornievskaia } 1008e0639dc5SOlga Kornievskaia 1009624322f1SOlga Kornievskaia int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy) 1010624322f1SOlga Kornievskaia { 1011624322f1SOlga Kornievskaia return nfs4_init_cp_state(nn, ©->cp_stateid, NFS4_COPY_STID); 1012624322f1SOlga Kornievskaia } 1013624322f1SOlga Kornievskaia 1014624322f1SOlga Kornievskaia struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, 1015624322f1SOlga Kornievskaia struct nfs4_stid *p_stid) 1016624322f1SOlga Kornievskaia { 1017624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 1018624322f1SOlga Kornievskaia 1019624322f1SOlga Kornievskaia cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL); 1020624322f1SOlga Kornievskaia if (!cps) 1021624322f1SOlga Kornievskaia return NULL; 102220b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 1023781fde1aSChuck Lever refcount_set(&cps->cp_stateid.cs_count, 1); 1024624322f1SOlga Kornievskaia if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID)) 1025624322f1SOlga Kornievskaia goto out_free; 1026624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1027624322f1SOlga Kornievskaia list_add(&cps->cp_list, &p_stid->sc_cp_list); 1028624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1029624322f1SOlga Kornievskaia return cps; 1030624322f1SOlga Kornievskaia out_free: 1031624322f1SOlga Kornievskaia kfree(cps); 1032624322f1SOlga Kornievskaia return NULL; 1033624322f1SOlga Kornievskaia } 1034624322f1SOlga Kornievskaia 1035624322f1SOlga Kornievskaia void nfs4_free_copy_state(struct nfsd4_copy *copy) 1036e0639dc5SOlga Kornievskaia { 1037e0639dc5SOlga Kornievskaia struct nfsd_net *nn; 1038e0639dc5SOlga Kornievskaia 1039781fde1aSChuck Lever WARN_ON_ONCE(copy->cp_stateid.cs_type != NFS4_COPY_STID); 1040e0639dc5SOlga Kornievskaia nn = net_generic(copy->cp_clp->net, nfsd_net_id); 1041e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1042624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 1043781fde1aSChuck Lever copy->cp_stateid.cs_stid.si_opaque.so_id); 1044624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1045624322f1SOlga Kornievskaia } 1046624322f1SOlga Kornievskaia 1047624322f1SOlga Kornievskaia static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid) 1048624322f1SOlga Kornievskaia { 1049624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 1050624322f1SOlga Kornievskaia struct nfsd_net *nn; 1051624322f1SOlga Kornievskaia 1052624322f1SOlga Kornievskaia nn = net_generic(net, nfsd_net_id); 1053624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1054624322f1SOlga Kornievskaia while (!list_empty(&stid->sc_cp_list)) { 1055624322f1SOlga Kornievskaia cps = list_first_entry(&stid->sc_cp_list, 1056624322f1SOlga Kornievskaia struct nfs4_cpntf_state, cp_list); 1057624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 1058624322f1SOlga Kornievskaia } 1059e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1060e0639dc5SOlga Kornievskaia } 1061e0639dc5SOlga Kornievskaia 1062b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 10634cdc951bSJ. Bruce Fields { 10646011695dSTrond Myklebust struct nfs4_stid *stid; 10656011695dSTrond Myklebust 1066d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 10676011695dSTrond Myklebust if (!stid) 10686011695dSTrond Myklebust return NULL; 10696011695dSTrond Myklebust 1070d19fb70dSKinglong Mee return openlockstateid(stid); 10716011695dSTrond Myklebust } 10726011695dSTrond Myklebust 10736011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 10746011695dSTrond Myklebust { 1075895ddf5eSJeff Layton struct nfs4_delegation *dp = delegstateid(stid); 1076895ddf5eSJeff Layton 1077895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&stid->sc_cp_list)); 1078895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&dp->dl_perfile)); 1079895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&dp->dl_perclnt)); 1080895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&dp->dl_recall_lru)); 10816011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 10826011695dSTrond Myklebust atomic_long_dec(&num_delegations); 10834cdc951bSJ. Bruce Fields } 10844cdc951bSJ. Bruce Fields 10856282cd56SNeilBrown /* 10866282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 10876282cd56SNeilBrown * out again straight away. 10886282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 10896282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 10906282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 10916282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 10926282cd56SNeilBrown * filter. 10936282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 10946282cd56SNeilBrown * unless both are empty of course. 10956282cd56SNeilBrown * 10966282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 10976282cd56SNeilBrown * low 3 bytes as hash-table indices. 10986282cd56SNeilBrown * 1099f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 11006282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 11016282cd56SNeilBrown * except when swapping the two filters. 11026282cd56SNeilBrown */ 1103f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 11046282cd56SNeilBrown static struct bloom_pair { 11056282cd56SNeilBrown int entries, old_entries; 1106b3f255efSArnd Bergmann time64_t swap_time; 11076282cd56SNeilBrown int new; /* index into 'set' */ 11086282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 11096282cd56SNeilBrown } blocked_delegations; 11106282cd56SNeilBrown 11116282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 11126282cd56SNeilBrown { 11136282cd56SNeilBrown u32 hash; 11146282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 11156282cd56SNeilBrown 11166282cd56SNeilBrown if (bd->entries == 0) 11176282cd56SNeilBrown return 0; 1118b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 1119f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 1120b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 11216282cd56SNeilBrown bd->entries -= bd->old_entries; 11226282cd56SNeilBrown bd->old_entries = bd->entries; 11236282cd56SNeilBrown memset(bd->set[bd->new], 0, 11246282cd56SNeilBrown sizeof(bd->set[0])); 11256282cd56SNeilBrown bd->new = 1-bd->new; 1126b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 11276282cd56SNeilBrown } 1128f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 11296282cd56SNeilBrown } 1130d8b26071SNeilBrown hash = jhash(&fh->fh_raw, fh->fh_size, 0); 11316282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 11326282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 11336282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 11346282cd56SNeilBrown return 1; 11356282cd56SNeilBrown 11366282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 11376282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 11386282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 11396282cd56SNeilBrown return 1; 11406282cd56SNeilBrown 11416282cd56SNeilBrown return 0; 11426282cd56SNeilBrown } 11436282cd56SNeilBrown 11446282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 11456282cd56SNeilBrown { 11466282cd56SNeilBrown u32 hash; 11476282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 11486282cd56SNeilBrown 1149d8b26071SNeilBrown hash = jhash(&fh->fh_raw, fh->fh_size, 0); 11506282cd56SNeilBrown 1151f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 11526282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 11536282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 11546282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 11556282cd56SNeilBrown if (bd->entries == 0) 1156b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 11576282cd56SNeilBrown bd->entries += 1; 1158f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 11596282cd56SNeilBrown } 11606282cd56SNeilBrown 11611da177e4SLinus Torvalds static struct nfs4_delegation * 116286d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 11638287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 11641da177e4SLinus Torvalds { 11651da177e4SLinus Torvalds struct nfs4_delegation *dp; 116602a3508dSTrond Myklebust long n; 11671da177e4SLinus Torvalds 11681da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 116902a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 117002a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 117102a3508dSTrond Myklebust goto out_dec; 1172bbf936edSJeff Layton if (delegation_blocked(&fp->fi_fhandle)) 117302a3508dSTrond Myklebust goto out_dec; 1174d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 11755b2d21c1SNeilBrown if (dp == NULL) 117602a3508dSTrond Myklebust goto out_dec; 11776011695dSTrond Myklebust 11782a74aba7SJ. Bruce Fields /* 11792a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 11806136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 11816136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 11822a74aba7SJ. Bruce Fields */ 11832a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 1184ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 1185ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 11861da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 11878287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 11888287f009SSachin Bhamare get_clnt_odstate(odstate); 118999c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 1190f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 119166af2579SDai Ngo dp->dl_recalled = false; 1192f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 11930162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 119486d29b10SJ. Bruce Fields get_nfs4_file(fp); 119586d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 11961da177e4SLinus Torvalds return dp; 119702a3508dSTrond Myklebust out_dec: 119802a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 119902a3508dSTrond Myklebust return NULL; 12001da177e4SLinus Torvalds } 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds void 12036011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 12041da177e4SLinus Torvalds { 120511b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 12066011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 12076011695dSTrond Myklebust 12084770d722SJeff Layton might_lock(&clp->cl_lock); 12094770d722SJeff Layton 1210a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 1211b401be22SJeff Layton wake_up_all(&close_wq); 12126011695dSTrond Myklebust return; 1213b401be22SJeff Layton } 12146011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 1215624322f1SOlga Kornievskaia nfs4_free_cpntf_statelist(clp->net, s); 12164770d722SJeff Layton spin_unlock(&clp->cl_lock); 12176011695dSTrond Myklebust s->sc_free(s); 121811b9164aSTrond Myklebust if (fp) 121911b9164aSTrond Myklebust put_nfs4_file(fp); 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds 12229767feb2SJeff Layton void 12239767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 12249767feb2SJeff Layton { 12259767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 12269767feb2SJeff Layton 12279767feb2SJeff Layton spin_lock(&stid->sc_lock); 12289767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 12299767feb2SJeff Layton src->si_generation = 1; 12309767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 12319767feb2SJeff Layton spin_unlock(&stid->sc_lock); 12329767feb2SJeff Layton } 12339767feb2SJeff Layton 1234353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 12351da177e4SLinus Torvalds { 1236eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 1237353601e7SJ. Bruce Fields 1238353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 1239353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 1240eb82dd39SJeff Layton swap(nf, fp->fi_deleg_file); 1241353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 1242353601e7SJ. Bruce Fields 1243eb82dd39SJeff Layton if (nf) 1244eb82dd39SJeff Layton nfsd_file_put(nf); 1245353601e7SJ. Bruce Fields } 1246353601e7SJ. Bruce Fields 1247353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 1248353601e7SJ. Bruce Fields { 1249cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 1250eb82dd39SJeff Layton struct nfsd_file *nf = fp->fi_deleg_file; 1251417c6629SJeff Layton 1252b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 1253b8232d33SJ. Bruce Fields 1254eb82dd39SJeff Layton vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); 1255353601e7SJ. Bruce Fields put_deleg_file(fp); 12561da177e4SLinus Torvalds } 12571da177e4SLinus Torvalds 12580af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 12590af6e690SJ. Bruce Fields { 12600af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 1261353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 12620af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 12630af6e690SJ. Bruce Fields } 12640af6e690SJ. Bruce Fields 1265cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 12666136d2b4SJ. Bruce Fields { 12673abdb607SJ. Bruce Fields s->sc_type = 0; 12686136d2b4SJ. Bruce Fields } 12696136d2b4SJ. Bruce Fields 127034ed9872SAndrew Elble /** 127168b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 127234ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 127334ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 127434ed9872SAndrew Elble * 127534ed9872SAndrew Elble * Return: 127668b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 127734ed9872SAndrew Elble */ 127834ed9872SAndrew Elble 127968b18f52SJ. Bruce Fields static bool 128068b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 1281931ee56cSBenny Halevy { 128234ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 128334ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 128434ed9872SAndrew Elble 1285cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 1286417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 1287931ee56cSBenny Halevy 128834ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 128934ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 129034ed9872SAndrew Elble if (clp == searchclp) { 129151d87bc2SFengguang Wu return true; 129234ed9872SAndrew Elble } 129334ed9872SAndrew Elble } 129451d87bc2SFengguang Wu return false; 129534ed9872SAndrew Elble } 129634ed9872SAndrew Elble 129734ed9872SAndrew Elble /** 129834ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 129934ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 130034ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 130134ed9872SAndrew Elble * 130234ed9872SAndrew Elble * Return: 130334ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 130434ed9872SAndrew Elble * 130534ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 130634ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 130734ed9872SAndrew Elble * 130834ed9872SAndrew Elble */ 130934ed9872SAndrew Elble 131034ed9872SAndrew Elble static int 131134ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 131234ed9872SAndrew Elble { 131334ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 131434ed9872SAndrew Elble 131534ed9872SAndrew Elble lockdep_assert_held(&state_lock); 131634ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 131734ed9872SAndrew Elble 131868b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 131968b18f52SJ. Bruce Fields return -EAGAIN; 1320a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 13213fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 1322931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 132334ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 132434ed9872SAndrew Elble return 0; 1325931ee56cSBenny Halevy } 1326931ee56cSBenny Halevy 1327548ec080SJ. Bruce Fields static bool delegation_hashed(struct nfs4_delegation *dp) 1328548ec080SJ. Bruce Fields { 1329548ec080SJ. Bruce Fields return !(list_empty(&dp->dl_perfile)); 1330548ec080SJ. Bruce Fields } 1331548ec080SJ. Bruce Fields 13323fcbbd24SJeff Layton static bool 133342690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 13341da177e4SLinus Torvalds { 133511b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 133602e1215fSJeff Layton 133742690676SJeff Layton lockdep_assert_held(&state_lock); 133842690676SJeff Layton 1339548ec080SJ. Bruce Fields if (!delegation_hashed(dp)) 13403fcbbd24SJeff Layton return false; 13413fcbbd24SJeff Layton 1342b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 1343d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 1344d55a166cSJeff Layton ++dp->dl_time; 1345417c6629SJeff Layton spin_lock(&fp->fi_lock); 1346931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 13471da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 134802e1215fSJeff Layton list_del_init(&dp->dl_perfile); 134902e1215fSJeff Layton spin_unlock(&fp->fi_lock); 13503fcbbd24SJeff Layton return true; 1351cbf7a75bSJ. Bruce Fields } 13523bd64a5bSJ. Bruce Fields 13533bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 13543bd64a5bSJ. Bruce Fields { 13553fcbbd24SJeff Layton bool unhashed; 13563fcbbd24SJeff Layton 135742690676SJeff Layton spin_lock(&state_lock); 13583fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 135942690676SJeff Layton spin_unlock(&state_lock); 13600af6e690SJ. Bruce Fields if (unhashed) 13610af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 13623fcbbd24SJeff Layton } 13633bd64a5bSJ. Bruce Fields 13643bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 13653bd64a5bSJ. Bruce Fields { 13663bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 13673bd64a5bSJ. Bruce Fields 13682d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 13692d4a532dSJeff Layton 1370a1c74569SChuck Lever trace_nfsd_stid_revoke(&dp->dl_stid); 1371a1c74569SChuck Lever 13720af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 13733bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 13740af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 13752d4a532dSJeff Layton spin_lock(&clp->cl_lock); 13762d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 13772d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 13783bd64a5bSJ. Bruce Fields } 13790af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 13803bd64a5bSJ. Bruce Fields } 13813bd64a5bSJ. Bruce Fields 13821da177e4SLinus Torvalds /* 13831da177e4SLinus Torvalds * SETCLIENTID state 13841da177e4SLinus Torvalds */ 13851da177e4SLinus Torvalds 1386ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1387ddc04c41SJ. Bruce Fields { 1388ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1389ddc04c41SJ. Bruce Fields } 1390ddc04c41SJ. Bruce Fields 13916b189105SScott Mayhew static unsigned int clientstr_hashval(struct xdr_netobj name) 1392ddc04c41SJ. Bruce Fields { 13936b189105SScott Mayhew return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; 1394ddc04c41SJ. Bruce Fields } 1395ddc04c41SJ. Bruce Fields 13961da177e4SLinus Torvalds /* 1397baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1398baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1399baeb4ff0SJeff Layton */ 1400baeb4ff0SJeff Layton static void 1401baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1402baeb4ff0SJeff Layton { 1403baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1404baeb4ff0SJeff Layton 1405baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1406baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1407baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1408baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1409baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1410baeb4ff0SJeff Layton } 1411baeb4ff0SJeff Layton 1412baeb4ff0SJeff Layton static void 1413baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1414baeb4ff0SJeff Layton { 1415baeb4ff0SJeff Layton int i; 1416baeb4ff0SJeff Layton bool change = false; 1417baeb4ff0SJeff Layton 1418baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1419baeb4ff0SJeff Layton if ((i & deny) != i) { 1420baeb4ff0SJeff Layton change = true; 1421baeb4ff0SJeff Layton clear_deny(i, stp); 1422baeb4ff0SJeff Layton } 1423baeb4ff0SJeff Layton } 1424baeb4ff0SJeff Layton 1425baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1426baeb4ff0SJeff Layton if (change) 142711b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1428baeb4ff0SJeff Layton } 1429baeb4ff0SJeff Layton 143082c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 143182c5ff1bSJeff Layton static void 143282c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 143382c5ff1bSJeff Layton { 143482c5ff1bSJeff Layton int i; 143511b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1436baeb4ff0SJeff Layton 1437baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1438baeb4ff0SJeff Layton recalculate_deny_mode(fp); 143982c5ff1bSJeff Layton 144082c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 144182c5ff1bSJeff Layton if (test_access(i, stp)) 144211b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 144382c5ff1bSJeff Layton clear_access(i, stp); 144482c5ff1bSJeff Layton } 144582c5ff1bSJeff Layton } 144682c5ff1bSJeff Layton 1447d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1448d50ffdedSKinglong Mee { 1449d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1450d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1451d50ffdedSKinglong Mee } 1452d50ffdedSKinglong Mee 14536b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 14546b180f0bSJeff Layton { 1455a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1456a819ecc1SJeff Layton 1457a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1458a819ecc1SJeff Layton 1459a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 14606b180f0bSJeff Layton return; 14618f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1462a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1463d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 14646b180f0bSJeff Layton } 14656b180f0bSJeff Layton 1466a451b123STrond Myklebust static bool 1467a451b123STrond Myklebust nfs4_ol_stateid_unhashed(const struct nfs4_ol_stateid *stp) 1468a451b123STrond Myklebust { 1469a451b123STrond Myklebust return list_empty(&stp->st_perfile); 1470a451b123STrond Myklebust } 1471a451b123STrond Myklebust 1472e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1473529d7b2aSJ. Bruce Fields { 147411b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 14751d31a253STrond Myklebust 14761c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 14771c755dc1SJeff Layton 1478e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1479e8568739SJeff Layton return false; 1480e8568739SJeff Layton 14811d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1482e8568739SJeff Layton list_del_init(&stp->st_perfile); 14831d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1484529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1485e8568739SJeff Layton return true; 1486529d7b2aSJ. Bruce Fields } 1487529d7b2aSJ. Bruce Fields 14886011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1489529d7b2aSJ. Bruce Fields { 14906011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 14914665e2baSJ. Bruce Fields 14928287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 14936011695dSTrond Myklebust release_all_access(stp); 1494d3134b10SJeff Layton if (stp->st_stateowner) 1495d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 1496019805feSDai Ngo WARN_ON(!list_empty(&stid->sc_cp_list)); 14976011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1498529d7b2aSJ. Bruce Fields } 1499529d7b2aSJ. Bruce Fields 1500b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1501529d7b2aSJ. Bruce Fields { 1502b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1503b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1504eb82dd39SJeff Layton struct nfsd_file *nf; 1505529d7b2aSJ. Bruce Fields 1506eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 1507eb82dd39SJeff Layton if (nf) { 1508eb82dd39SJeff Layton get_file(nf->nf_file); 1509eb82dd39SJeff Layton filp_close(nf->nf_file, (fl_owner_t)lo); 1510eb82dd39SJeff Layton nfsd_file_put(nf); 1511eb82dd39SJeff Layton } 1512b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1513b49e084dSJeff Layton } 1514b49e084dSJeff Layton 15152c41beb0SJeff Layton /* 15162c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 15172c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 15182c41beb0SJeff Layton * reaplist for later destruction. 15192c41beb0SJeff Layton */ 15202c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 15212c41beb0SJeff Layton struct list_head *reaplist) 15222c41beb0SJeff Layton { 15232c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 15242c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 15252c41beb0SJeff Layton 15262c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 15272c41beb0SJeff Layton 15282c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 15292c41beb0SJeff Layton 1530a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 15312c41beb0SJeff Layton wake_up_all(&close_wq); 15322c41beb0SJeff Layton return; 15332c41beb0SJeff Layton } 15342c41beb0SJeff Layton 15352c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 15362c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 15372c41beb0SJeff Layton } 15382c41beb0SJeff Layton 1539e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 15403c1c995cSJeff Layton { 1541f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 15423c1c995cSJeff Layton 1543a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1544a451b123STrond Myklebust return false; 15453c1c995cSJeff Layton list_del_init(&stp->st_locks); 1546cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1547a451b123STrond Myklebust return true; 15483c1c995cSJeff Layton } 15493c1c995cSJeff Layton 15505adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1551b49e084dSJeff Layton { 1552f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1553e8568739SJeff Layton bool unhashed; 15541c755dc1SJeff Layton 1555f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1556e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1557f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1558e8568739SJeff Layton if (unhashed) 15596011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1560529d7b2aSJ. Bruce Fields } 1561529d7b2aSJ. Bruce Fields 1562c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1563529d7b2aSJ. Bruce Fields { 1564d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1565c58c6610STrond Myklebust 1566d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1567c58c6610STrond Myklebust 15688f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 15698f4b54c5SJeff Layton } 15708f4b54c5SJeff Layton 15712c41beb0SJeff Layton /* 15722c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 15732c41beb0SJeff Layton * fully unhashed. 15742c41beb0SJeff Layton */ 15752c41beb0SJeff Layton static void 15762c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 15772c41beb0SJeff Layton { 15782c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1579fb94d766SKinglong Mee struct nfs4_file *fp; 15802c41beb0SJeff Layton 15812c41beb0SJeff Layton might_sleep(); 15822c41beb0SJeff Layton 15832c41beb0SJeff Layton while (!list_empty(reaplist)) { 15842c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 15852c41beb0SJeff Layton st_locks); 15862c41beb0SJeff Layton list_del(&stp->st_locks); 1587fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 15882c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1589fb94d766SKinglong Mee if (fp) 1590fb94d766SKinglong Mee put_nfs4_file(fp); 15912c41beb0SJeff Layton } 15922c41beb0SJeff Layton } 15932c41beb0SJeff Layton 1594d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1595d83017f9SJeff Layton struct list_head *reaplist) 15963c87b9b7STrond Myklebust { 15973c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 15983c87b9b7STrond Myklebust 1599e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1600e8568739SJeff Layton 16013c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 16023c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 16033c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1604e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1605d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1606529d7b2aSJ. Bruce Fields } 1607529d7b2aSJ. Bruce Fields } 1608529d7b2aSJ. Bruce Fields 1609e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1610d83017f9SJeff Layton struct list_head *reaplist) 16112283963fSJ. Bruce Fields { 16122c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 16132c41beb0SJeff Layton 1614a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1615a451b123STrond Myklebust return false; 1616d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1617a451b123STrond Myklebust return true; 161838c387b5SJ. Bruce Fields } 161938c387b5SJ. Bruce Fields 162038c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 162138c387b5SJ. Bruce Fields { 16222c41beb0SJeff Layton LIST_HEAD(reaplist); 16232c41beb0SJeff Layton 16242c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1625e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 16262c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 16272c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 16282c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 16292283963fSJ. Bruce Fields } 16302283963fSJ. Bruce Fields 16317ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1632f1d110caSJ. Bruce Fields { 1633d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 16347ffb5880STrond Myklebust 1635d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 16367ffb5880STrond Myklebust 16378f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 16388f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1639f1d110caSJ. Bruce Fields } 1640f1d110caSJ. Bruce Fields 1641f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1642f7a4d872SJ. Bruce Fields { 1643217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1644217526e7SJeff Layton nfsd_net_id); 1645217526e7SJeff Layton struct nfs4_ol_stateid *s; 1646f7a4d872SJ. Bruce Fields 1647217526e7SJeff Layton spin_lock(&nn->client_lock); 1648217526e7SJeff Layton s = oo->oo_last_closed_stid; 1649f7a4d872SJ. Bruce Fields if (s) { 1650d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1651f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1652f7a4d872SJ. Bruce Fields } 1653217526e7SJeff Layton spin_unlock(&nn->client_lock); 1654217526e7SJeff Layton if (s) 1655217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1656f7a4d872SJ. Bruce Fields } 1657f7a4d872SJ. Bruce Fields 16582c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 16598f4b54c5SJeff Layton { 16608f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1661d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 16622c41beb0SJeff Layton struct list_head reaplist; 16637ffb5880STrond Myklebust 16642c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 16657ffb5880STrond Myklebust 1666d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 16677ffb5880STrond Myklebust unhash_openowner_locked(oo); 16682c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 16692c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 16702c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1671e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 16722c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 16732c41beb0SJeff Layton } 1674d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 16752c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1676f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 16776b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1678f1d110caSJ. Bruce Fields } 1679f1d110caSJ. Bruce Fields 16805282fd72SMarc Eshel static inline int 16815282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 16825282fd72SMarc Eshel { 16835282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 16845282fd72SMarc Eshel 16855282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 16865282fd72SMarc Eshel } 16875282fd72SMarc Eshel 1688135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 16895282fd72SMarc Eshel static inline void 16905282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 16915282fd72SMarc Eshel { 16925282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 16935282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 16945282fd72SMarc Eshel } 16958f199b82STrond Myklebust #else 16968f199b82STrond Myklebust static inline void 16978f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 16988f199b82STrond Myklebust { 16998f199b82STrond Myklebust } 17008f199b82STrond Myklebust #endif 17018f199b82STrond Myklebust 17029411b1d4SJ. Bruce Fields /* 17039411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 17049411b1d4SJ. Bruce Fields * won't be used for replay. 17059411b1d4SJ. Bruce Fields */ 17069411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 17079411b1d4SJ. Bruce Fields { 17089411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 17099411b1d4SJ. Bruce Fields 17109411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 17119411b1d4SJ. Bruce Fields return; 17129411b1d4SJ. Bruce Fields 17139411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 171458fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 17159411b1d4SJ. Bruce Fields return; 17169411b1d4SJ. Bruce Fields } 17179411b1d4SJ. Bruce Fields if (!so) 17189411b1d4SJ. Bruce Fields return; 17199411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 17209411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 17219411b1d4SJ. Bruce Fields so->so_seqid++; 17229411b1d4SJ. Bruce Fields return; 17239411b1d4SJ. Bruce Fields } 17245282fd72SMarc Eshel 1725ec6b5d7bSAndy Adamson static void 1726ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1727ec6b5d7bSAndy Adamson { 1728ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1729ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1730ec6b5d7bSAndy Adamson 1731ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1732ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1733ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1734ec6b5d7bSAndy Adamson sid->reserved = 0; 1735ec6b5d7bSAndy Adamson } 1736ec6b5d7bSAndy Adamson 1737ec6b5d7bSAndy Adamson /* 1738a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1739a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1740a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1741a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1742a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1743a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1744a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1745a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1746a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1747a649637cSAndy Adamson * for the SEQUENCE op response: 1748ec6b5d7bSAndy Adamson */ 1749a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1750a649637cSAndy Adamson 1751557ce264SAndy Adamson static void 1752557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1753557ce264SAndy Adamson { 1754557ce264SAndy Adamson int i; 1755557ce264SAndy Adamson 175653da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 175753da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1758557ce264SAndy Adamson kfree(ses->se_slots[i]); 1759557ce264SAndy Adamson } 176053da6a53SJ. Bruce Fields } 1761557ce264SAndy Adamson 1762efe0cb6dSJ. Bruce Fields /* 1763efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1764efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1765efe0cb6dSJ. Bruce Fields */ 176655c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1767efe0cb6dSJ. Bruce Fields { 176855c760cfSJ. Bruce Fields u32 size; 1769efe0cb6dSJ. Bruce Fields 177055c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 177155c760cfSJ. Bruce Fields size = 0; 177255c760cfSJ. Bruce Fields else 177355c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 177455c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1775557ce264SAndy Adamson } 1776557ce264SAndy Adamson 17775b6feee9SJ. Bruce Fields /* 17785b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 17795b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 178042b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 17815b6feee9SJ. Bruce Fields */ 17822030ca56SNeilBrown static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 17835b6feee9SJ. Bruce Fields { 178455c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 178555c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 1786c54f24e3SJ. Bruce Fields unsigned long avail, total_avail; 17872030ca56SNeilBrown unsigned int scale_factor; 17885b6feee9SJ. Bruce Fields 17895b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 17907f49fd5dSNeilBrown if (nfsd_drc_max_mem > nfsd_drc_mem_used) 1791c54f24e3SJ. Bruce Fields total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 17927f49fd5dSNeilBrown else 17937f49fd5dSNeilBrown /* We have handed out more space than we chose in 17947f49fd5dSNeilBrown * set_max_drc() to allow. That isn't really a 17957f49fd5dSNeilBrown * problem as long as that doesn't make us think we 17967f49fd5dSNeilBrown * have lots more due to integer overflow. 17977f49fd5dSNeilBrown */ 17987f49fd5dSNeilBrown total_avail = 0; 1799c54f24e3SJ. Bruce Fields avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1800de766e57SJ. Bruce Fields /* 18012030ca56SNeilBrown * Never use more than a fraction of the remaining memory, 18027f49fd5dSNeilBrown * unless it's the only way to give this client a slot. 18032030ca56SNeilBrown * The chosen fraction is either 1/8 or 1/number of threads, 18042030ca56SNeilBrown * whichever is smaller. This ensures there are adequate 18052030ca56SNeilBrown * slots to support multiple clients per thread. 18067f49fd5dSNeilBrown * Give the client one slot even if that would require 18077f49fd5dSNeilBrown * over-allocation--it is better than failure. 1808de766e57SJ. Bruce Fields */ 18092030ca56SNeilBrown scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); 18102030ca56SNeilBrown 18112030ca56SNeilBrown avail = clamp_t(unsigned long, avail, slotsize, 18122030ca56SNeilBrown total_avail/scale_factor); 18135b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 18147f49fd5dSNeilBrown num = max_t(int, num, 1); 18155b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 18165b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 18175b6feee9SJ. Bruce Fields 18185b6feee9SJ. Bruce Fields return num; 18195b6feee9SJ. Bruce Fields } 18205b6feee9SJ. Bruce Fields 182155c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 18225b6feee9SJ. Bruce Fields { 182355c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 182455c760cfSJ. Bruce Fields 18255b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 182655c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 18275b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 18285b6feee9SJ. Bruce Fields } 18295b6feee9SJ. Bruce Fields 183060810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 183160810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 18325b6feee9SJ. Bruce Fields { 183360810e54SKinglong Mee int numslots = fattrs->maxreqs; 183460810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 18355b6feee9SJ. Bruce Fields struct nfsd4_session *new; 183685a0d0c9SXiu Jianfeng int i; 1837ec6b5d7bSAndy Adamson 183885a0d0c9SXiu Jianfeng BUILD_BUG_ON(struct_size(new, se_slots, NFSD_MAX_SLOTS_PER_SESSION) 183985a0d0c9SXiu Jianfeng > PAGE_SIZE); 1840ec6b5d7bSAndy Adamson 184185a0d0c9SXiu Jianfeng new = kzalloc(struct_size(new, se_slots, numslots), GFP_KERNEL); 18426c18ba9fSAlexandros Batsakis if (!new) 18435b6feee9SJ. Bruce Fields return NULL; 1844ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 18455b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 184655c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 18475b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1848ec6b5d7bSAndy Adamson goto out_free; 1849ec6b5d7bSAndy Adamson } 185060810e54SKinglong Mee 185160810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 185260810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 185360810e54SKinglong Mee 18545b6feee9SJ. Bruce Fields return new; 18555b6feee9SJ. Bruce Fields out_free: 18565b6feee9SJ. Bruce Fields while (i--) 18575b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 18585b6feee9SJ. Bruce Fields kfree(new); 18595b6feee9SJ. Bruce Fields return NULL; 18605b6feee9SJ. Bruce Fields } 18615b6feee9SJ. Bruce Fields 186219cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 186319cf5c02SJ. Bruce Fields { 186419cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 186519cf5c02SJ. Bruce Fields kfree(c); 186619cf5c02SJ. Bruce Fields } 186719cf5c02SJ. Bruce Fields 186819cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 186919cf5c02SJ. Bruce Fields { 187019cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 187119cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 187219cf5c02SJ. Bruce Fields 1873806d65b6SChuck Lever trace_nfsd_cb_lost(clp); 1874806d65b6SChuck Lever 187519cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 187619cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 187719cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 187819cf5c02SJ. Bruce Fields free_conn(c); 187919cf5c02SJ. Bruce Fields } 1880eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 18812e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 188219cf5c02SJ. Bruce Fields } 188319cf5c02SJ. Bruce Fields 1884d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1885c7662518SJ. Bruce Fields { 1886c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1887c7662518SJ. Bruce Fields 1888c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1889c7662518SJ. Bruce Fields if (!conn) 1890db90681dSJ. Bruce Fields return NULL; 1891c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1892c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1893d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1894db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1895db90681dSJ. Bruce Fields return conn; 1896db90681dSJ. Bruce Fields } 1897db90681dSJ. Bruce Fields 1898328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1899328ead28SJ. Bruce Fields { 1900328ead28SJ. Bruce Fields conn->cn_session = ses; 1901328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1902328ead28SJ. Bruce Fields } 1903328ead28SJ. Bruce Fields 1904db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1905db90681dSJ. Bruce Fields { 1906db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1907c7662518SJ. Bruce Fields 1908c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1909328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1910c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1911db90681dSJ. Bruce Fields } 1912c7662518SJ. Bruce Fields 191321b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1914db90681dSJ. Bruce Fields { 191519cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 191621b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1917db90681dSJ. Bruce Fields } 1918db90681dSJ. Bruce Fields 1919e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1920db90681dSJ. Bruce Fields { 192121b75b01SJ. Bruce Fields int ret; 1922db90681dSJ. Bruce Fields 1923db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 192421b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 192521b75b01SJ. Bruce Fields if (ret) 192621b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 192721b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 192857a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 192957a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1930c7662518SJ. Bruce Fields } 1931c7662518SJ. Bruce Fields 1932e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 19331d1bc8f2SJ. Bruce Fields { 19341d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 19351d1bc8f2SJ. Bruce Fields 1936e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 19371d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1938e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 19391d1bc8f2SJ. Bruce Fields } 19401d1bc8f2SJ. Bruce Fields 19411d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 194219cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1943c7662518SJ. Bruce Fields { 194419cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 194519cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 194619cf5c02SJ. Bruce Fields 194719cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 194819cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 194919cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 195019cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 195119cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 195219cf5c02SJ. Bruce Fields 195319cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 195419cf5c02SJ. Bruce Fields free_conn(c); 195519cf5c02SJ. Bruce Fields 195619cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 195719cf5c02SJ. Bruce Fields } 195819cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1959c7662518SJ. Bruce Fields } 1960c7662518SJ. Bruce Fields 19611377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 19621377b69eSJ. Bruce Fields { 19631377b69eSJ. Bruce Fields free_session_slots(ses); 19641377b69eSJ. Bruce Fields kfree(ses); 19651377b69eSJ. Bruce Fields } 19661377b69eSJ. Bruce Fields 196766b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1968508dc6e1SBenny Halevy { 1969c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 197055c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1971c7662518SJ. Bruce Fields __free_session(ses); 1972a827bcb2SJ. Bruce Fields } 1973ec6b5d7bSAndy Adamson 1974135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1975a827bcb2SJ. Bruce Fields { 1976a827bcb2SJ. Bruce Fields int idx; 19771872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1978a827bcb2SJ. Bruce Fields 1979ec6b5d7bSAndy Adamson new->se_client = clp; 1980ec6b5d7bSAndy Adamson gen_sessionid(new); 1981ec6b5d7bSAndy Adamson 1982c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1983c7662518SJ. Bruce Fields 1984ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1985ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 19868b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1987c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 198866b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 19895b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 19901872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 19914c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1992ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 19934c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 199460810e54SKinglong Mee 1995b0d2e42cSChuck Lever { 1996edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1997dcbeaa68SJ. Bruce Fields /* 1998dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1999dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 2000dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 2001dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 2002dcbeaa68SJ. Bruce Fields * future: 2003dcbeaa68SJ. Bruce Fields */ 2004edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 2005edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 2006edd76786SJ. Bruce Fields } 2007ec6b5d7bSAndy Adamson } 2008ec6b5d7bSAndy Adamson 20099089f1b4SBenny Halevy /* caller must hold client_lock */ 20105282fd72SMarc Eshel static struct nfsd4_session * 2011d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 20125282fd72SMarc Eshel { 20135282fd72SMarc Eshel struct nfsd4_session *elem; 20145282fd72SMarc Eshel int idx; 20151872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 20165282fd72SMarc Eshel 20170a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20180a880a28STrond Myklebust 20195282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 20205282fd72SMarc Eshel idx = hash_sessionid(sessionid); 20215282fd72SMarc Eshel /* Search in the appropriate list */ 20221872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 20235282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 20245282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 20255282fd72SMarc Eshel return elem; 20265282fd72SMarc Eshel } 20275282fd72SMarc Eshel } 20285282fd72SMarc Eshel 20295282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 20305282fd72SMarc Eshel return NULL; 20315282fd72SMarc Eshel } 20325282fd72SMarc Eshel 2033d4e19e70STrond Myklebust static struct nfsd4_session * 2034d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 2035d4e19e70STrond Myklebust __be32 *ret) 2036d4e19e70STrond Myklebust { 2037d4e19e70STrond Myklebust struct nfsd4_session *session; 2038d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 2039d4e19e70STrond Myklebust 2040d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 2041d4e19e70STrond Myklebust if (!session) 2042d4e19e70STrond Myklebust goto out; 2043d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 2044d4e19e70STrond Myklebust if (status) 2045d4e19e70STrond Myklebust session = NULL; 2046d4e19e70STrond Myklebust out: 2047d4e19e70STrond Myklebust *ret = status; 2048d4e19e70STrond Myklebust return session; 2049d4e19e70STrond Myklebust } 2050d4e19e70STrond Myklebust 20519089f1b4SBenny Halevy /* caller must hold client_lock */ 20527116ed6bSAndy Adamson static void 20535282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 20547116ed6bSAndy Adamson { 20550a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 20560a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20570a880a28STrond Myklebust 20580a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20590a880a28STrond Myklebust 20607116ed6bSAndy Adamson list_del(&ses->se_hash); 20614c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 20627116ed6bSAndy Adamson list_del(&ses->se_perclnt); 20634c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 20645282fd72SMarc Eshel } 20655282fd72SMarc Eshel 20661da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 20671da177e4SLinus Torvalds static int 20682c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 20691da177e4SLinus Torvalds { 2070bbc7f33aSJ. Bruce Fields /* 2071bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 2072bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 2073bbc7f33aSJ. Bruce Fields * a safe assumption: 2074bbc7f33aSJ. Bruce Fields */ 2075bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 20761da177e4SLinus Torvalds return 0; 2077dd5e3fbcSChuck Lever trace_nfsd_clid_stale(clid); 20781da177e4SLinus Torvalds return 1; 20791da177e4SLinus Torvalds } 20801da177e4SLinus Torvalds 20811da177e4SLinus Torvalds /* 20821da177e4SLinus Torvalds * XXX Should we use a slab cache ? 20831da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 20841da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 20851da177e4SLinus Torvalds */ 20860926c395SDai Ngo static struct nfs4_client *alloc_client(struct xdr_netobj name, 20870926c395SDai Ngo struct nfsd_net *nn) 20881da177e4SLinus Torvalds { 20891da177e4SLinus Torvalds struct nfs4_client *clp; 2090d4f0489fSTrond Myklebust int i; 20911da177e4SLinus Torvalds 20924271c2c0SDai Ngo if (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) { 20934271c2c0SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 20944271c2c0SDai Ngo return NULL; 20954271c2c0SDai Ngo } 20969258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 209735bba9a3SJ. Bruce Fields if (clp == NULL) 209835bba9a3SJ. Bruce Fields return NULL; 20996f4859b8SJ. Bruce Fields xdr_netobj_dup(&clp->cl_name, &name, GFP_KERNEL); 2100d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 2101d4f0489fSTrond Myklebust goto err_no_name; 21026da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 21036da2ec56SKees Cook sizeof(struct list_head), 21046da2ec56SKees Cook GFP_KERNEL); 2105d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 2106d4f0489fSTrond Myklebust goto err_no_hashtbl; 2107d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 2108d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 21095694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 21105694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 211114ed14ccSJ. Bruce Fields atomic_set(&clp->cl_rpc_users, 0); 21125694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 211366af2579SDai Ngo clp->cl_state = NFSD4_ACTIVE; 21140926c395SDai Ngo atomic_inc(&nn->nfs4_client_count); 211566af2579SDai Ngo atomic_set(&clp->cl_delegs_in_recall, 0); 21165694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 21175694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 21185694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 21195694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 21205694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 21219cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 21229cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 21239cf514ccSChristoph Hellwig #endif 2124e0639dc5SOlga Kornievskaia INIT_LIST_HEAD(&clp->async_copies); 2125e0639dc5SOlga Kornievskaia spin_lock_init(&clp->async_lock); 21265694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 21275694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 21281da177e4SLinus Torvalds return clp; 2129d4f0489fSTrond Myklebust err_no_hashtbl: 2130d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 2131d4f0489fSTrond Myklebust err_no_name: 21329258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 2133d4f0489fSTrond Myklebust return NULL; 21341da177e4SLinus Torvalds } 21351da177e4SLinus Torvalds 213659f8e91bSJ. Bruce Fields static void __free_client(struct kref *k) 213759f8e91bSJ. Bruce Fields { 2138e8a79fb1SJ. Bruce Fields struct nfsdfs_client *c = container_of(k, struct nfsdfs_client, cl_ref); 2139e8a79fb1SJ. Bruce Fields struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs); 214059f8e91bSJ. Bruce Fields 214159f8e91bSJ. Bruce Fields free_svc_cred(&clp->cl_cred); 214259f8e91bSJ. Bruce Fields kfree(clp->cl_ownerstr_hashtbl); 214359f8e91bSJ. Bruce Fields kfree(clp->cl_name.data); 214479123444SJ. Bruce Fields kfree(clp->cl_nii_domain.data); 214579123444SJ. Bruce Fields kfree(clp->cl_nii_name.data); 214659f8e91bSJ. Bruce Fields idr_destroy(&clp->cl_stateids); 2147*44df6f43SDai Ngo kfree(clp->cl_ra); 214859f8e91bSJ. Bruce Fields kmem_cache_free(client_slab, clp); 214959f8e91bSJ. Bruce Fields } 215059f8e91bSJ. Bruce Fields 2151297e57a2SYueHaibing static void drop_client(struct nfs4_client *clp) 215259f8e91bSJ. Bruce Fields { 2153e8a79fb1SJ. Bruce Fields kref_put(&clp->cl_nfsdfs.cl_ref, __free_client); 215459f8e91bSJ. Bruce Fields } 215559f8e91bSJ. Bruce Fields 21564dd86e15STrond Myklebust static void 21571da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 21581da177e4SLinus Torvalds { 2159792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 2160792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2161792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 2162792c95ddSJ. Bruce Fields se_perclnt); 2163792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 216466b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 216566b2b9b2SJ. Bruce Fields free_session(ses); 2166792c95ddSJ. Bruce Fields } 21674cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 216889c905beSJ. Bruce Fields if (clp->cl_nfsd_dentry) { 2169e8a79fb1SJ. Bruce Fields nfsd_client_rmdir(clp->cl_nfsd_dentry); 217089c905beSJ. Bruce Fields clp->cl_nfsd_dentry = NULL; 217189c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 217289c905beSJ. Bruce Fields } 217359f8e91bSJ. Bruce Fields drop_client(clp); 21741da177e4SLinus Torvalds } 21751da177e4SLinus Torvalds 217684d38ac9SBenny Halevy /* must be called under the client_lock */ 21774beb345bSTrond Myklebust static void 217884d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 217984d38ac9SBenny Halevy { 21804beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2181792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2182792c95ddSJ. Bruce Fields 21830a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 21840a880a28STrond Myklebust 21854beb345bSTrond Myklebust /* Mark the client as expired! */ 21864beb345bSTrond Myklebust clp->cl_time = 0; 21874beb345bSTrond Myklebust /* Make it invisible */ 21884beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 21894beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 21904beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 21914beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 21924beb345bSTrond Myklebust else 21934beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 21944beb345bSTrond Myklebust } 21954beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 21964c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 2197792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 2198792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 21994c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 220084d38ac9SBenny Halevy } 220184d38ac9SBenny Halevy 22021da177e4SLinus Torvalds static void 22034beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 22044beb345bSTrond Myklebust { 22054beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 22064beb345bSTrond Myklebust 22074beb345bSTrond Myklebust spin_lock(&nn->client_lock); 22084beb345bSTrond Myklebust unhash_client_locked(clp); 22094beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 22104beb345bSTrond Myklebust } 22114beb345bSTrond Myklebust 221297403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 221397403d95SJeff Layton { 221414ed14ccSJ. Bruce Fields if (atomic_read(&clp->cl_rpc_users)) 221597403d95SJeff Layton return nfserr_jukebox; 221697403d95SJeff Layton unhash_client_locked(clp); 221797403d95SJeff Layton return nfs_ok; 221897403d95SJeff Layton } 221997403d95SJeff Layton 22204beb345bSTrond Myklebust static void 22214beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 22221da177e4SLinus Torvalds { 22230926c395SDai Ngo struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 222468ef3bc3SJeff Layton int i; 2225fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 22261da177e4SLinus Torvalds struct nfs4_delegation *dp; 22271da177e4SLinus Torvalds struct list_head reaplist; 22281da177e4SLinus Torvalds 22291da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 2230cdc97505SBenny Halevy spin_lock(&state_lock); 2231ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 2232ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 22333fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 223442690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 22351da177e4SLinus Torvalds } 2236cdc97505SBenny Halevy spin_unlock(&state_lock); 22371da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 22381da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 223942690676SJeff Layton list_del_init(&dp->dl_recall_lru); 22400af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 22411da177e4SLinus Torvalds } 22422d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 2243c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 22442d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 22456011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 2246956c4feeSBenny Halevy } 2247ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 2248fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 2249b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 2250fe0750e5SJ. Bruce Fields release_openowner(oo); 22511da177e4SLinus Torvalds } 225268ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 225368ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 225468ef3bc3SJeff Layton 225568ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 225668ef3bc3SJeff Layton so_strhash) { 225768ef3bc3SJeff Layton /* Should be no openowners at this point */ 225868ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 225968ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 226068ef3bc3SJeff Layton } 226168ef3bc3SJeff Layton } 22629cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 2263e0639dc5SOlga Kornievskaia nfsd4_shutdown_copy(clp); 22646ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 22652bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 22662bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 22670926c395SDai Ngo atomic_add_unless(&nn->nfs4_client_count, -1, 0); 22683a4ea23dSDai Ngo nfsd4_dec_courtesy_client_count(nn, clp); 2269b12a05cbSJ. Bruce Fields free_client(clp); 227089c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 22711da177e4SLinus Torvalds } 22721da177e4SLinus Torvalds 22734beb345bSTrond Myklebust static void 22744beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 22754beb345bSTrond Myklebust { 22764beb345bSTrond Myklebust unhash_client(clp); 22774beb345bSTrond Myklebust __destroy_client(clp); 22784beb345bSTrond Myklebust } 22794beb345bSTrond Myklebust 2280362063a5SScott Mayhew static void inc_reclaim_complete(struct nfs4_client *clp) 2281362063a5SScott Mayhew { 2282362063a5SScott Mayhew struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2283362063a5SScott Mayhew 2284362063a5SScott Mayhew if (!nn->track_reclaim_completes) 2285362063a5SScott Mayhew return; 2286362063a5SScott Mayhew if (!nfsd4_find_reclaim_client(clp->cl_name, nn)) 2287362063a5SScott Mayhew return; 2288362063a5SScott Mayhew if (atomic_inc_return(&nn->nr_reclaim_complete) == 2289362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) { 2290362063a5SScott Mayhew printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n", 2291362063a5SScott Mayhew clp->net->ns.inum); 2292362063a5SScott Mayhew nfsd4_end_grace(nn); 2293362063a5SScott Mayhew } 2294362063a5SScott Mayhew } 2295362063a5SScott Mayhew 22960d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 22970d22f68fSJ. Bruce Fields { 22984beb345bSTrond Myklebust unhash_client(clp); 22990d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 23004beb345bSTrond Myklebust __destroy_client(clp); 23010d22f68fSJ. Bruce Fields } 23020d22f68fSJ. Bruce Fields 230335bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 230435bba9a3SJ. Bruce Fields { 230535bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 230635bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 23071da177e4SLinus Torvalds } 23081da177e4SLinus Torvalds 230935bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 231035bba9a3SJ. Bruce Fields { 23111da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 23121da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 23131da177e4SLinus Torvalds } 23141da177e4SLinus Torvalds 231550043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 231650043859SJ. Bruce Fields { 23172f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 23182f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 23192f10fdcbSNeilBrown GFP_KERNEL); 23209abdda5dSChuck Lever target->cr_targ_princ = kstrdup(source->cr_targ_princ, GFP_KERNEL); 23212f10fdcbSNeilBrown if ((source->cr_principal && !target->cr_principal) || 23229abdda5dSChuck Lever (source->cr_raw_principal && !target->cr_raw_principal) || 23239abdda5dSChuck Lever (source->cr_targ_princ && !target->cr_targ_princ)) 23242f10fdcbSNeilBrown return -ENOMEM; 232550043859SJ. Bruce Fields 2326d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 23271da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 23281da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 23291da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 23301da177e4SLinus Torvalds get_group_info(target->cr_group_info); 23310dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 23320dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 23330dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 233403a4e1f6SJ. Bruce Fields return 0; 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds 2337ef17af2aSRasmus Villemoes static int 2338ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 2339ac55fdc4SJeff Layton { 2340ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2341ef17af2aSRasmus Villemoes return -1; 2342ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2343ef17af2aSRasmus Villemoes return 1; 2344ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2345ac55fdc4SJeff Layton } 2346ac55fdc4SJeff Layton 23471da177e4SLinus Torvalds static int 2348599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2349599e0a22SJ. Bruce Fields { 2350599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds 23531da177e4SLinus Torvalds static int 2354599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2355599e0a22SJ. Bruce Fields { 2356599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 23571da177e4SLinus Torvalds } 23581da177e4SLinus Torvalds 23598fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 23608fbba96eSJ. Bruce Fields { 23618fbba96eSJ. Bruce Fields int i; 23628fbba96eSJ. Bruce Fields 23638fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 23648fbba96eSJ. Bruce Fields return false; 23658fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 236681243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 23678fbba96eSJ. Bruce Fields return false; 23688fbba96eSJ. Bruce Fields return true; 23698fbba96eSJ. Bruce Fields } 23708fbba96eSJ. Bruce Fields 237168eb3508SJ. Bruce Fields /* 237268eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 237368eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 237468eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 237568eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 237668eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 237768eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 237868eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 237968eb3508SJ. Bruce Fields */ 238068eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 238168eb3508SJ. Bruce Fields { 238268eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 238368eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 238468eb3508SJ. Bruce Fields } 238568eb3508SJ. Bruce Fields 238668eb3508SJ. Bruce Fields 23875559b50aSVivek Trivedi static bool 2388599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2389599e0a22SJ. Bruce Fields { 239068eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 23916fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 23926fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 23938fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 23948fbba96eSJ. Bruce Fields return false; 23959abdda5dSChuck Lever /* XXX: check that cr_targ_princ fields match ? */ 23968fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 23978fbba96eSJ. Bruce Fields return true; 23988fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 23998fbba96eSJ. Bruce Fields return false; 24005559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 24011da177e4SLinus Torvalds } 24021da177e4SLinus Torvalds 240357266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 240457266a6eSJ. Bruce Fields { 240557266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 240657266a6eSJ. Bruce Fields u32 service; 240757266a6eSJ. Bruce Fields 2408c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2409c4720591SJ. Bruce Fields return false; 241057266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 241157266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 241257266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 241357266a6eSJ. Bruce Fields } 241457266a6eSJ. Bruce Fields 2415dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 241657266a6eSJ. Bruce Fields { 241757266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 241857266a6eSJ. Bruce Fields 241957266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 242057266a6eSJ. Bruce Fields return true; 242157266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 242257266a6eSJ. Bruce Fields return false; 242357266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 242457266a6eSJ. Bruce Fields return false; 2425414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2426414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2427414ca017SJ. Bruce Fields cr->cr_raw_principal); 242857266a6eSJ. Bruce Fields if (!cr->cr_principal) 242957266a6eSJ. Bruce Fields return false; 243057266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 243157266a6eSJ. Bruce Fields } 243257266a6eSJ. Bruce Fields 2433294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2434deda2faaSJ. Bruce Fields { 2435ab4684d1SChuck Lever __be32 verf[2]; 24361da177e4SLinus Torvalds 2437f419992cSJeff Layton /* 2438f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2439f419992cSJeff Layton * __force to keep sparse happy 2440f419992cSJeff Layton */ 24419104ae49SArnd Bergmann verf[0] = (__force __be32)(u32)ktime_get_real_seconds(); 244219311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2443ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 24441da177e4SLinus Torvalds } 24451da177e4SLinus Torvalds 2446294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2447294ac32eSJeff Layton { 24489cc76801SArnd Bergmann clp->cl_clientid.cl_boot = (u32)nn->boot_time; 2449294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2450294ac32eSJeff Layton gen_confirm(clp, nn); 2451294ac32eSJeff Layton } 2452294ac32eSJeff Layton 24534770d722SJeff Layton static struct nfs4_stid * 24544770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 24554581d140SJ. Bruce Fields { 24563abdb607SJ. Bruce Fields struct nfs4_stid *ret; 24573abdb607SJ. Bruce Fields 24583abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 24593abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 24603abdb607SJ. Bruce Fields return NULL; 24613abdb607SJ. Bruce Fields return ret; 24624581d140SJ. Bruce Fields } 24634d71ab87SJ. Bruce Fields 24644770d722SJeff Layton static struct nfs4_stid * 24654770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2466f459e453SJ. Bruce Fields { 2467f459e453SJ. Bruce Fields struct nfs4_stid *s; 2468f459e453SJ. Bruce Fields 24694770d722SJeff Layton spin_lock(&cl->cl_lock); 24704770d722SJeff Layton s = find_stateid_locked(cl, t); 24712d3f9668STrond Myklebust if (s != NULL) { 24722d3f9668STrond Myklebust if (typemask & s->sc_type) 2473a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 24742d3f9668STrond Myklebust else 24754770d722SJeff Layton s = NULL; 24762d3f9668STrond Myklebust } 24774770d722SJeff Layton spin_unlock(&cl->cl_lock); 24784d71ab87SJ. Bruce Fields return s; 24794581d140SJ. Bruce Fields } 24804581d140SJ. Bruce Fields 2481a204f25eSJ. Bruce Fields static struct nfs4_client *get_nfsdfs_clp(struct inode *inode) 2482a204f25eSJ. Bruce Fields { 2483a204f25eSJ. Bruce Fields struct nfsdfs_client *nc; 2484a204f25eSJ. Bruce Fields nc = get_nfsdfs_client(inode); 2485a204f25eSJ. Bruce Fields if (!nc) 2486a204f25eSJ. Bruce Fields return NULL; 2487a204f25eSJ. Bruce Fields return container_of(nc, struct nfs4_client, cl_nfsdfs); 2488a204f25eSJ. Bruce Fields } 2489a204f25eSJ. Bruce Fields 2490169319f1SJ. Bruce Fields static void seq_quote_mem(struct seq_file *m, char *data, int len) 2491169319f1SJ. Bruce Fields { 2492169319f1SJ. Bruce Fields seq_printf(m, "\""); 2493c0546391SAndy Shevchenko seq_escape_mem(m, data, len, ESCAPE_HEX | ESCAPE_NAP | ESCAPE_APPEND, "\"\\"); 2494169319f1SJ. Bruce Fields seq_printf(m, "\""); 2495169319f1SJ. Bruce Fields } 2496169319f1SJ. Bruce Fields 24973518c866SDave Wysochanski static const char *cb_state2str(int state) 24983518c866SDave Wysochanski { 24993518c866SDave Wysochanski switch (state) { 25003518c866SDave Wysochanski case NFSD4_CB_UP: 25013518c866SDave Wysochanski return "UP"; 25023518c866SDave Wysochanski case NFSD4_CB_UNKNOWN: 25033518c866SDave Wysochanski return "UNKNOWN"; 25043518c866SDave Wysochanski case NFSD4_CB_DOWN: 25053518c866SDave Wysochanski return "DOWN"; 25063518c866SDave Wysochanski case NFSD4_CB_FAULT: 25073518c866SDave Wysochanski return "FAULT"; 25083518c866SDave Wysochanski } 25093518c866SDave Wysochanski return "UNDEFINED"; 25103518c866SDave Wysochanski } 25113518c866SDave Wysochanski 251297ad4031SJ. Bruce Fields static int client_info_show(struct seq_file *m, void *v) 251397ad4031SJ. Bruce Fields { 25141d7f6b30SChenXiaoSong struct inode *inode = file_inode(m->file); 251597ad4031SJ. Bruce Fields struct nfs4_client *clp; 251697ad4031SJ. Bruce Fields u64 clid; 251797ad4031SJ. Bruce Fields 2518a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2519a204f25eSJ. Bruce Fields if (!clp) 252097ad4031SJ. Bruce Fields return -ENXIO; 252197ad4031SJ. Bruce Fields memcpy(&clid, &clp->cl_clientid, sizeof(clid)); 252297ad4031SJ. Bruce Fields seq_printf(m, "clientid: 0x%llx\n", clid); 2523169319f1SJ. Bruce Fields seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); 2524e9488d5aSDai Ngo 2525e9488d5aSDai Ngo if (clp->cl_state == NFSD4_COURTESY) 2526e9488d5aSDai Ngo seq_puts(m, "status: courtesy\n"); 2527e9488d5aSDai Ngo else if (clp->cl_state == NFSD4_EXPIRABLE) 2528e9488d5aSDai Ngo seq_puts(m, "status: expirable\n"); 2529e9488d5aSDai Ngo else if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 2530472d155aSNeilBrown seq_puts(m, "status: confirmed\n"); 2531472d155aSNeilBrown else 2532472d155aSNeilBrown seq_puts(m, "status: unconfirmed\n"); 2533e9488d5aSDai Ngo seq_printf(m, "seconds from last renew: %lld\n", 2534e9488d5aSDai Ngo ktime_get_boottime_seconds() - clp->cl_time); 2535169319f1SJ. Bruce Fields seq_printf(m, "name: "); 2536169319f1SJ. Bruce Fields seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); 2537169319f1SJ. Bruce Fields seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); 253879123444SJ. Bruce Fields if (clp->cl_nii_domain.data) { 253979123444SJ. Bruce Fields seq_printf(m, "Implementation domain: "); 254079123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_domain.data, 254179123444SJ. Bruce Fields clp->cl_nii_domain.len); 254279123444SJ. Bruce Fields seq_printf(m, "\nImplementation name: "); 254379123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_name.data, clp->cl_nii_name.len); 2544e29f4703SArnd Bergmann seq_printf(m, "\nImplementation time: [%lld, %ld]\n", 254579123444SJ. Bruce Fields clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); 254679123444SJ. Bruce Fields } 25473518c866SDave Wysochanski seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state)); 25483518c866SDave Wysochanski seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr); 254997ad4031SJ. Bruce Fields drop_client(clp); 255097ad4031SJ. Bruce Fields 255197ad4031SJ. Bruce Fields return 0; 255297ad4031SJ. Bruce Fields } 255397ad4031SJ. Bruce Fields 25541d7f6b30SChenXiaoSong DEFINE_SHOW_ATTRIBUTE(client_info); 255597ad4031SJ. Bruce Fields 255678599c42SJ. Bruce Fields static void *states_start(struct seq_file *s, loff_t *pos) 255778599c42SJ. Bruce Fields __acquires(&clp->cl_lock) 255878599c42SJ. Bruce Fields { 255978599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 256078599c42SJ. Bruce Fields unsigned long id = *pos; 256178599c42SJ. Bruce Fields void *ret; 256278599c42SJ. Bruce Fields 256378599c42SJ. Bruce Fields spin_lock(&clp->cl_lock); 256478599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 256578599c42SJ. Bruce Fields *pos = id; 256678599c42SJ. Bruce Fields return ret; 256778599c42SJ. Bruce Fields } 256878599c42SJ. Bruce Fields 256978599c42SJ. Bruce Fields static void *states_next(struct seq_file *s, void *v, loff_t *pos) 257078599c42SJ. Bruce Fields { 257178599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 257278599c42SJ. Bruce Fields unsigned long id = *pos; 257378599c42SJ. Bruce Fields void *ret; 257478599c42SJ. Bruce Fields 257578599c42SJ. Bruce Fields id = *pos; 257678599c42SJ. Bruce Fields id++; 257778599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 257878599c42SJ. Bruce Fields *pos = id; 257978599c42SJ. Bruce Fields return ret; 258078599c42SJ. Bruce Fields } 258178599c42SJ. Bruce Fields 258278599c42SJ. Bruce Fields static void states_stop(struct seq_file *s, void *v) 258378599c42SJ. Bruce Fields __releases(&clp->cl_lock) 258478599c42SJ. Bruce Fields { 258578599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 258678599c42SJ. Bruce Fields 258778599c42SJ. Bruce Fields spin_unlock(&clp->cl_lock); 258878599c42SJ. Bruce Fields } 258978599c42SJ. Bruce Fields 2590580da465SAchilles Gaikwad static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f) 2591580da465SAchilles Gaikwad { 2592580da465SAchilles Gaikwad seq_printf(s, "filename: \"%pD2\"", f->nf_file); 2593580da465SAchilles Gaikwad } 2594580da465SAchilles Gaikwad 2595fd4f83fdSJeff Layton static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) 259678599c42SJ. Bruce Fields { 2597427f5f83SChuck Lever struct inode *inode = file_inode(f->nf_file); 259878599c42SJ. Bruce Fields 259978599c42SJ. Bruce Fields seq_printf(s, "superblock: \"%02x:%02x:%ld\"", 260078599c42SJ. Bruce Fields MAJOR(inode->i_sb->s_dev), 260178599c42SJ. Bruce Fields MINOR(inode->i_sb->s_dev), 260278599c42SJ. Bruce Fields inode->i_ino); 260378599c42SJ. Bruce Fields } 260478599c42SJ. Bruce Fields 260578599c42SJ. Bruce Fields static void nfs4_show_owner(struct seq_file *s, struct nfs4_stateowner *oo) 260678599c42SJ. Bruce Fields { 260778599c42SJ. Bruce Fields seq_printf(s, "owner: "); 260878599c42SJ. Bruce Fields seq_quote_mem(s, oo->so_owner.data, oo->so_owner.len); 260978599c42SJ. Bruce Fields } 261078599c42SJ. Bruce Fields 2611ace7ade4SJ. Bruce Fields static void nfs4_show_stateid(struct seq_file *s, stateid_t *stid) 2612ace7ade4SJ. Bruce Fields { 2613ee590d25SJ. Bruce Fields seq_printf(s, "0x%.8x", stid->si_generation); 2614ee590d25SJ. Bruce Fields seq_printf(s, "%12phN", &stid->si_opaque); 2615ace7ade4SJ. Bruce Fields } 2616ace7ade4SJ. Bruce Fields 261778599c42SJ. Bruce Fields static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) 261878599c42SJ. Bruce Fields { 261978599c42SJ. Bruce Fields struct nfs4_ol_stateid *ols; 262078599c42SJ. Bruce Fields struct nfs4_file *nf; 2621fd4f83fdSJeff Layton struct nfsd_file *file; 262278599c42SJ. Bruce Fields struct nfs4_stateowner *oo; 262378599c42SJ. Bruce Fields unsigned int access, deny; 262478599c42SJ. Bruce Fields 262578599c42SJ. Bruce Fields if (st->sc_type != NFS4_OPEN_STID && st->sc_type != NFS4_LOCK_STID) 262678599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 262778599c42SJ. Bruce Fields ols = openlockstateid(st); 262878599c42SJ. Bruce Fields oo = ols->st_stateowner; 262978599c42SJ. Bruce Fields nf = st->sc_file; 2630e0aa6510SJeff Layton 2631e0aa6510SJeff Layton spin_lock(&nf->fi_lock); 2632e0aa6510SJeff Layton file = find_any_file_locked(nf); 26339affa435SJ. Bruce Fields if (!file) 2634e0aa6510SJeff Layton goto out; 263578599c42SJ. Bruce Fields 2636ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2637ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2638ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: open, "); 263978599c42SJ. Bruce Fields 264078599c42SJ. Bruce Fields access = bmap_to_share_mode(ols->st_access_bmap); 264178599c42SJ. Bruce Fields deny = bmap_to_share_mode(ols->st_deny_bmap); 264278599c42SJ. Bruce Fields 2643c4b77edbSJ. Bruce Fields seq_printf(s, "access: %s%s, ", 264478599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_READ ? "r" : "-", 264578599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 2646c4b77edbSJ. Bruce Fields seq_printf(s, "deny: %s%s, ", 264778599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", 264878599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 264978599c42SJ. Bruce Fields 265078599c42SJ. Bruce Fields nfs4_show_superblock(s, file); 265178599c42SJ. Bruce Fields seq_printf(s, ", "); 2652580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2653580da465SAchilles Gaikwad seq_printf(s, ", "); 265478599c42SJ. Bruce Fields nfs4_show_owner(s, oo); 265578599c42SJ. Bruce Fields seq_printf(s, " }\n"); 2656e0aa6510SJeff Layton out: 2657e0aa6510SJeff Layton spin_unlock(&nf->fi_lock); 265878599c42SJ. Bruce Fields return 0; 265978599c42SJ. Bruce Fields } 266078599c42SJ. Bruce Fields 266116d36e09SJ. Bruce Fields static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) 266216d36e09SJ. Bruce Fields { 266316d36e09SJ. Bruce Fields struct nfs4_ol_stateid *ols; 266416d36e09SJ. Bruce Fields struct nfs4_file *nf; 2665fd4f83fdSJeff Layton struct nfsd_file *file; 266616d36e09SJ. Bruce Fields struct nfs4_stateowner *oo; 266716d36e09SJ. Bruce Fields 266816d36e09SJ. Bruce Fields ols = openlockstateid(st); 266916d36e09SJ. Bruce Fields oo = ols->st_stateowner; 267016d36e09SJ. Bruce Fields nf = st->sc_file; 2671e0aa6510SJeff Layton spin_lock(&nf->fi_lock); 2672e0aa6510SJeff Layton file = find_any_file_locked(nf); 26739affa435SJ. Bruce Fields if (!file) 2674e0aa6510SJeff Layton goto out; 267516d36e09SJ. Bruce Fields 2676ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2677ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2678ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: lock, "); 267916d36e09SJ. Bruce Fields 268016d36e09SJ. Bruce Fields /* 268116d36e09SJ. Bruce Fields * Note: a lock stateid isn't really the same thing as a lock, 268216d36e09SJ. Bruce Fields * it's the locking state held by one owner on a file, and there 268316d36e09SJ. Bruce Fields * may be multiple (or no) lock ranges associated with it. 268416d36e09SJ. Bruce Fields * (Same for the matter is true of open stateids.) 268516d36e09SJ. Bruce Fields */ 268616d36e09SJ. Bruce Fields 268716d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 268816d36e09SJ. Bruce Fields /* XXX: open stateid? */ 268916d36e09SJ. Bruce Fields seq_printf(s, ", "); 2690580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2691580da465SAchilles Gaikwad seq_printf(s, ", "); 269216d36e09SJ. Bruce Fields nfs4_show_owner(s, oo); 269316d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2694e0aa6510SJeff Layton out: 2695e0aa6510SJeff Layton spin_unlock(&nf->fi_lock); 269616d36e09SJ. Bruce Fields return 0; 269716d36e09SJ. Bruce Fields } 269816d36e09SJ. Bruce Fields 269916d36e09SJ. Bruce Fields static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) 270016d36e09SJ. Bruce Fields { 270116d36e09SJ. Bruce Fields struct nfs4_delegation *ds; 270216d36e09SJ. Bruce Fields struct nfs4_file *nf; 2703eb82dd39SJeff Layton struct nfsd_file *file; 270416d36e09SJ. Bruce Fields 270516d36e09SJ. Bruce Fields ds = delegstateid(st); 270616d36e09SJ. Bruce Fields nf = st->sc_file; 2707e0aa6510SJeff Layton spin_lock(&nf->fi_lock); 2708e0aa6510SJeff Layton file = find_deleg_file_locked(nf); 27099affa435SJ. Bruce Fields if (!file) 2710e0aa6510SJeff Layton goto out; 271116d36e09SJ. Bruce Fields 2712ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2713ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2714ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: deleg, "); 271516d36e09SJ. Bruce Fields 271616d36e09SJ. Bruce Fields /* Kinda dead code as long as we only support read delegs: */ 271716d36e09SJ. Bruce Fields seq_printf(s, "access: %s, ", 271816d36e09SJ. Bruce Fields ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); 271916d36e09SJ. Bruce Fields 272016d36e09SJ. Bruce Fields /* XXX: lease time, whether it's being recalled. */ 272116d36e09SJ. Bruce Fields 272216d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 2723580da465SAchilles Gaikwad seq_printf(s, ", "); 2724580da465SAchilles Gaikwad nfs4_show_fname(s, file); 272516d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2726e0aa6510SJeff Layton out: 2727e0aa6510SJeff Layton spin_unlock(&nf->fi_lock); 272816d36e09SJ. Bruce Fields return 0; 272916d36e09SJ. Bruce Fields } 273016d36e09SJ. Bruce Fields 27310c4b62b0SJ. Bruce Fields static int nfs4_show_layout(struct seq_file *s, struct nfs4_stid *st) 27320c4b62b0SJ. Bruce Fields { 27330c4b62b0SJ. Bruce Fields struct nfs4_layout_stateid *ls; 2734eb82dd39SJeff Layton struct nfsd_file *file; 27350c4b62b0SJ. Bruce Fields 27360c4b62b0SJ. Bruce Fields ls = container_of(st, struct nfs4_layout_stateid, ls_stid); 27370c4b62b0SJ. Bruce Fields file = ls->ls_file; 27380c4b62b0SJ. Bruce Fields 2739ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2740ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2741ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: layout, "); 27420c4b62b0SJ. Bruce Fields 27430c4b62b0SJ. Bruce Fields /* XXX: What else would be useful? */ 27440c4b62b0SJ. Bruce Fields 27450c4b62b0SJ. Bruce Fields nfs4_show_superblock(s, file); 2746580da465SAchilles Gaikwad seq_printf(s, ", "); 2747580da465SAchilles Gaikwad nfs4_show_fname(s, file); 27480c4b62b0SJ. Bruce Fields seq_printf(s, " }\n"); 27490c4b62b0SJ. Bruce Fields 27500c4b62b0SJ. Bruce Fields return 0; 27510c4b62b0SJ. Bruce Fields } 27520c4b62b0SJ. Bruce Fields 275378599c42SJ. Bruce Fields static int states_show(struct seq_file *s, void *v) 275478599c42SJ. Bruce Fields { 275578599c42SJ. Bruce Fields struct nfs4_stid *st = v; 275678599c42SJ. Bruce Fields 275778599c42SJ. Bruce Fields switch (st->sc_type) { 275878599c42SJ. Bruce Fields case NFS4_OPEN_STID: 275978599c42SJ. Bruce Fields return nfs4_show_open(s, st); 276016d36e09SJ. Bruce Fields case NFS4_LOCK_STID: 276116d36e09SJ. Bruce Fields return nfs4_show_lock(s, st); 276216d36e09SJ. Bruce Fields case NFS4_DELEG_STID: 276316d36e09SJ. Bruce Fields return nfs4_show_deleg(s, st); 27640c4b62b0SJ. Bruce Fields case NFS4_LAYOUT_STID: 27650c4b62b0SJ. Bruce Fields return nfs4_show_layout(s, st); 276678599c42SJ. Bruce Fields default: 276778599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 276878599c42SJ. Bruce Fields } 276916d36e09SJ. Bruce Fields /* XXX: copy stateids? */ 277078599c42SJ. Bruce Fields } 277178599c42SJ. Bruce Fields 277278599c42SJ. Bruce Fields static struct seq_operations states_seq_ops = { 277378599c42SJ. Bruce Fields .start = states_start, 277478599c42SJ. Bruce Fields .next = states_next, 277578599c42SJ. Bruce Fields .stop = states_stop, 277678599c42SJ. Bruce Fields .show = states_show 277778599c42SJ. Bruce Fields }; 277878599c42SJ. Bruce Fields 277978599c42SJ. Bruce Fields static int client_states_open(struct inode *inode, struct file *file) 278078599c42SJ. Bruce Fields { 278178599c42SJ. Bruce Fields struct seq_file *s; 278278599c42SJ. Bruce Fields struct nfs4_client *clp; 278378599c42SJ. Bruce Fields int ret; 278478599c42SJ. Bruce Fields 2785a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2786a204f25eSJ. Bruce Fields if (!clp) 278778599c42SJ. Bruce Fields return -ENXIO; 278878599c42SJ. Bruce Fields 278978599c42SJ. Bruce Fields ret = seq_open(file, &states_seq_ops); 279078599c42SJ. Bruce Fields if (ret) 279178599c42SJ. Bruce Fields return ret; 279278599c42SJ. Bruce Fields s = file->private_data; 279378599c42SJ. Bruce Fields s->private = clp; 279478599c42SJ. Bruce Fields return 0; 279578599c42SJ. Bruce Fields } 279678599c42SJ. Bruce Fields 279778599c42SJ. Bruce Fields static int client_opens_release(struct inode *inode, struct file *file) 279878599c42SJ. Bruce Fields { 279978599c42SJ. Bruce Fields struct seq_file *m = file->private_data; 280078599c42SJ. Bruce Fields struct nfs4_client *clp = m->private; 280178599c42SJ. Bruce Fields 280278599c42SJ. Bruce Fields /* XXX: alternatively, we could get/drop in seq start/stop */ 280378599c42SJ. Bruce Fields drop_client(clp); 280478599c42SJ. Bruce Fields return 0; 280578599c42SJ. Bruce Fields } 280678599c42SJ. Bruce Fields 280778599c42SJ. Bruce Fields static const struct file_operations client_states_fops = { 280878599c42SJ. Bruce Fields .open = client_states_open, 280978599c42SJ. Bruce Fields .read = seq_read, 281078599c42SJ. Bruce Fields .llseek = seq_lseek, 281178599c42SJ. Bruce Fields .release = client_opens_release, 281278599c42SJ. Bruce Fields }; 281378599c42SJ. Bruce Fields 281489c905beSJ. Bruce Fields /* 281589c905beSJ. Bruce Fields * Normally we refuse to destroy clients that are in use, but here the 281689c905beSJ. Bruce Fields * administrator is telling us to just do it. We also want to wait 281789c905beSJ. Bruce Fields * so the caller has a guarantee that the client's locks are gone by 281889c905beSJ. Bruce Fields * the time the write returns: 281989c905beSJ. Bruce Fields */ 2820297e57a2SYueHaibing static void force_expire_client(struct nfs4_client *clp) 282189c905beSJ. Bruce Fields { 282289c905beSJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 282389c905beSJ. Bruce Fields bool already_expired; 282489c905beSJ. Bruce Fields 28252958d2eeSChuck Lever trace_nfsd_clid_admin_expired(&clp->cl_clientid); 28262958d2eeSChuck Lever 2827f7104cc1SJ. Bruce Fields spin_lock(&nn->client_lock); 282889c905beSJ. Bruce Fields clp->cl_time = 0; 2829f7104cc1SJ. Bruce Fields spin_unlock(&nn->client_lock); 283089c905beSJ. Bruce Fields 283189c905beSJ. Bruce Fields wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0); 283289c905beSJ. Bruce Fields spin_lock(&nn->client_lock); 283389c905beSJ. Bruce Fields already_expired = list_empty(&clp->cl_lru); 283489c905beSJ. Bruce Fields if (!already_expired) 283589c905beSJ. Bruce Fields unhash_client_locked(clp); 283689c905beSJ. Bruce Fields spin_unlock(&nn->client_lock); 283789c905beSJ. Bruce Fields 283889c905beSJ. Bruce Fields if (!already_expired) 283989c905beSJ. Bruce Fields expire_client(clp); 284089c905beSJ. Bruce Fields else 284189c905beSJ. Bruce Fields wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL); 284289c905beSJ. Bruce Fields } 284389c905beSJ. Bruce Fields 284489c905beSJ. Bruce Fields static ssize_t client_ctl_write(struct file *file, const char __user *buf, 284589c905beSJ. Bruce Fields size_t size, loff_t *pos) 284689c905beSJ. Bruce Fields { 284789c905beSJ. Bruce Fields char *data; 284889c905beSJ. Bruce Fields struct nfs4_client *clp; 284989c905beSJ. Bruce Fields 285089c905beSJ. Bruce Fields data = simple_transaction_get(file, buf, size); 285189c905beSJ. Bruce Fields if (IS_ERR(data)) 285289c905beSJ. Bruce Fields return PTR_ERR(data); 285389c905beSJ. Bruce Fields if (size != 7 || 0 != memcmp(data, "expire\n", 7)) 285489c905beSJ. Bruce Fields return -EINVAL; 285589c905beSJ. Bruce Fields clp = get_nfsdfs_clp(file_inode(file)); 285689c905beSJ. Bruce Fields if (!clp) 285789c905beSJ. Bruce Fields return -ENXIO; 285889c905beSJ. Bruce Fields force_expire_client(clp); 285989c905beSJ. Bruce Fields drop_client(clp); 286089c905beSJ. Bruce Fields return 7; 286189c905beSJ. Bruce Fields } 286289c905beSJ. Bruce Fields 286389c905beSJ. Bruce Fields static const struct file_operations client_ctl_fops = { 286489c905beSJ. Bruce Fields .write = client_ctl_write, 286589c905beSJ. Bruce Fields .release = simple_transaction_release, 286689c905beSJ. Bruce Fields }; 286789c905beSJ. Bruce Fields 286897ad4031SJ. Bruce Fields static const struct tree_descr client_files[] = { 286997ad4031SJ. Bruce Fields [0] = {"info", &client_info_fops, S_IRUSR}, 287078599c42SJ. Bruce Fields [1] = {"states", &client_states_fops, S_IRUSR}, 28716cbfad5fSPetr Vorel [2] = {"ctl", &client_ctl_fops, S_IWUSR}, 287278599c42SJ. Bruce Fields [3] = {""}, 287397ad4031SJ. Bruce Fields }; 287497ad4031SJ. Bruce Fields 2875*44df6f43SDai Ngo static int 2876*44df6f43SDai Ngo nfsd4_cb_recall_any_done(struct nfsd4_callback *cb, 2877*44df6f43SDai Ngo struct rpc_task *task) 2878*44df6f43SDai Ngo { 2879*44df6f43SDai Ngo switch (task->tk_status) { 2880*44df6f43SDai Ngo case -NFS4ERR_DELAY: 2881*44df6f43SDai Ngo rpc_delay(task, 2 * HZ); 2882*44df6f43SDai Ngo return 0; 2883*44df6f43SDai Ngo default: 2884*44df6f43SDai Ngo return 1; 2885*44df6f43SDai Ngo } 2886*44df6f43SDai Ngo } 2887*44df6f43SDai Ngo 2888*44df6f43SDai Ngo static void 2889*44df6f43SDai Ngo nfsd4_cb_recall_any_release(struct nfsd4_callback *cb) 2890*44df6f43SDai Ngo { 2891*44df6f43SDai Ngo struct nfs4_client *clp = cb->cb_clp; 2892*44df6f43SDai Ngo struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2893*44df6f43SDai Ngo 2894*44df6f43SDai Ngo spin_lock(&nn->client_lock); 2895*44df6f43SDai Ngo clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags); 2896*44df6f43SDai Ngo put_client_renew_locked(clp); 2897*44df6f43SDai Ngo spin_unlock(&nn->client_lock); 2898*44df6f43SDai Ngo } 2899*44df6f43SDai Ngo 2900*44df6f43SDai Ngo static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = { 2901*44df6f43SDai Ngo .done = nfsd4_cb_recall_any_done, 2902*44df6f43SDai Ngo .release = nfsd4_cb_recall_any_release, 2903*44df6f43SDai Ngo }; 2904*44df6f43SDai Ngo 29052216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2906b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2907b09333c4SRicardo Labiaga { 2908b09333c4SRicardo Labiaga struct nfs4_client *clp; 2909b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 291003a4e1f6SJ. Bruce Fields int ret; 2911c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2912e8a79fb1SJ. Bruce Fields struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2913472d155aSNeilBrown struct dentry *dentries[ARRAY_SIZE(client_files)]; 2914b09333c4SRicardo Labiaga 29150926c395SDai Ngo clp = alloc_client(name, nn); 2916b09333c4SRicardo Labiaga if (clp == NULL) 2917b09333c4SRicardo Labiaga return NULL; 2918b09333c4SRicardo Labiaga 291903a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 292003a4e1f6SJ. Bruce Fields if (ret) { 2921b09333c4SRicardo Labiaga free_client(clp); 2922b09333c4SRicardo Labiaga return NULL; 2923b09333c4SRicardo Labiaga } 2924e8a79fb1SJ. Bruce Fields gen_clid(clp, nn); 2925e8a79fb1SJ. Bruce Fields kref_init(&clp->cl_nfsdfs.cl_ref); 29260162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 292720b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 2928b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2929b09333c4SRicardo Labiaga copy_verf(clp, verf); 29303bade247SJ. Bruce Fields memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); 2931edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2932c212cecfSStanislav Kinsbursky clp->net = net; 2933472d155aSNeilBrown clp->cl_nfsd_dentry = nfsd_client_mkdir( 2934472d155aSNeilBrown nn, &clp->cl_nfsdfs, 293597ad4031SJ. Bruce Fields clp->cl_clientid.cl_id - nn->clientid_base, 2936472d155aSNeilBrown client_files, dentries); 2937472d155aSNeilBrown clp->cl_nfsd_info_dentry = dentries[0]; 2938e8a79fb1SJ. Bruce Fields if (!clp->cl_nfsd_dentry) { 2939e8a79fb1SJ. Bruce Fields free_client(clp); 2940e8a79fb1SJ. Bruce Fields return NULL; 2941e8a79fb1SJ. Bruce Fields } 2942*44df6f43SDai Ngo clp->cl_ra = kzalloc(sizeof(*clp->cl_ra), GFP_KERNEL); 2943*44df6f43SDai Ngo if (!clp->cl_ra) { 2944*44df6f43SDai Ngo free_client(clp); 2945*44df6f43SDai Ngo return NULL; 2946*44df6f43SDai Ngo } 2947*44df6f43SDai Ngo clp->cl_ra_time = 0; 2948*44df6f43SDai Ngo nfsd4_init_cb(&clp->cl_ra->ra_cb, clp, &nfsd4_cb_recall_any_ops, 2949*44df6f43SDai Ngo NFSPROC4_CLNT_CB_RECALL_ANY); 2950b09333c4SRicardo Labiaga return clp; 2951b09333c4SRicardo Labiaga } 2952b09333c4SRicardo Labiaga 2953fd39ca9aSNeilBrown static void 2954ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2955ac55fdc4SJeff Layton { 2956ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2957ac55fdc4SJeff Layton struct nfs4_client *clp; 2958ac55fdc4SJeff Layton 2959ac55fdc4SJeff Layton while (*new) { 2960ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2961ac55fdc4SJeff Layton parent = *new; 2962ac55fdc4SJeff Layton 2963ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2964ac55fdc4SJeff Layton new = &((*new)->rb_left); 2965ac55fdc4SJeff Layton else 2966ac55fdc4SJeff Layton new = &((*new)->rb_right); 2967ac55fdc4SJeff Layton } 2968ac55fdc4SJeff Layton 2969ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2970ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2971ac55fdc4SJeff Layton } 2972ac55fdc4SJeff Layton 2973ac55fdc4SJeff Layton static struct nfs4_client * 2974ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2975ac55fdc4SJeff Layton { 2976ef17af2aSRasmus Villemoes int cmp; 2977ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2978ac55fdc4SJeff Layton struct nfs4_client *clp; 2979ac55fdc4SJeff Layton 2980ac55fdc4SJeff Layton while (node) { 2981ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2982ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2983ac55fdc4SJeff Layton if (cmp > 0) 2984ac55fdc4SJeff Layton node = node->rb_left; 2985ac55fdc4SJeff Layton else if (cmp < 0) 2986ac55fdc4SJeff Layton node = node->rb_right; 2987ac55fdc4SJeff Layton else 2988ac55fdc4SJeff Layton return clp; 2989ac55fdc4SJeff Layton } 2990ac55fdc4SJeff Layton return NULL; 2991ac55fdc4SJeff Layton } 2992ac55fdc4SJeff Layton 2993ac55fdc4SJeff Layton static void 2994ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 29951da177e4SLinus Torvalds { 29961da177e4SLinus Torvalds unsigned int idhashval; 29970a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 29981da177e4SLinus Torvalds 29990a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 30000a880a28STrond Myklebust 3001ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 3002a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 30031da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 30040a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 30053dbacee6STrond Myklebust renew_client_locked(clp); 30061da177e4SLinus Torvalds } 30071da177e4SLinus Torvalds 3008fd39ca9aSNeilBrown static void 30091da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 30101da177e4SLinus Torvalds { 30111da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 30128daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 30131da177e4SLinus Torvalds 30140a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 30150a880a28STrond Myklebust 30168daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 3017a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 3018382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 3019934bd07fSJ. Bruce Fields set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 30207e3b32acSChuck Lever trace_nfsd_clid_confirmed(&clp->cl_clientid); 30213dbacee6STrond Myklebust renew_client_locked(clp); 30221da177e4SLinus Torvalds } 30231da177e4SLinus Torvalds 30241da177e4SLinus Torvalds static struct nfs4_client * 3025bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 30261da177e4SLinus Torvalds { 30271da177e4SLinus Torvalds struct nfs4_client *clp; 30281da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 30291da177e4SLinus Torvalds 3030bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 3031a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 3032d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 3033d15c077eSJ. Bruce Fields return NULL; 30343dbacee6STrond Myklebust renew_client_locked(clp); 30351da177e4SLinus Torvalds return clp; 30361da177e4SLinus Torvalds } 3037a50d2ad1SJ. Bruce Fields } 30381da177e4SLinus Torvalds return NULL; 30391da177e4SLinus Torvalds } 30401da177e4SLinus Torvalds 30411da177e4SLinus Torvalds static struct nfs4_client * 3042bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 3043bfa85e83SJ. Bruce Fields { 3044bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 3045bfa85e83SJ. Bruce Fields 30460a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3047bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 3048bfa85e83SJ. Bruce Fields } 3049bfa85e83SJ. Bruce Fields 3050bfa85e83SJ. Bruce Fields static struct nfs4_client * 30510a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 30521da177e4SLinus Torvalds { 3053bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 30541da177e4SLinus Torvalds 30550a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3056bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 30571da177e4SLinus Torvalds } 30581da177e4SLinus Torvalds 30596e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 3060a1bcecd2SAndy Adamson { 30616e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 3062a1bcecd2SAndy Adamson } 3063a1bcecd2SAndy Adamson 306428ce6054SNeilBrown static struct nfs4_client * 3065382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 306628ce6054SNeilBrown { 30670a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3068382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 306928ce6054SNeilBrown } 307028ce6054SNeilBrown 307128ce6054SNeilBrown static struct nfs4_client * 3072a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 307328ce6054SNeilBrown { 30740a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3075a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 307628ce6054SNeilBrown } 307728ce6054SNeilBrown 3078fd39ca9aSNeilBrown static void 30796f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 30801da177e4SLinus Torvalds { 308107263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 30826f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 30836f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 30847077ecbaSJeff Layton unsigned short expected_family; 30851da177e4SLinus Torvalds 30867077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 30877077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 30887077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 30897077ecbaSJeff Layton expected_family = AF_INET; 30907077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 30917077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 30927077ecbaSJeff Layton expected_family = AF_INET6; 30937077ecbaSJeff Layton else 30941da177e4SLinus Torvalds goto out_err; 30951da177e4SLinus Torvalds 3096c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 3097aa9a4ec7SJeff Layton se->se_callback_addr_len, 309807263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 309907263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 3100aa9a4ec7SJeff Layton 310107263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 31021da177e4SLinus Torvalds goto out_err; 3103aa9a4ec7SJeff Layton 310407263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 310507263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 3106fbf4665fSJeff Layton 310707263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 310807263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 3109849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 31101eace0d1SChuck Lever trace_nfsd_cb_args(clp, conn); 31111da177e4SLinus Torvalds return; 31121da177e4SLinus Torvalds out_err: 311307263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 311407263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 31151eace0d1SChuck Lever trace_nfsd_cb_nodelegs(clp); 31161da177e4SLinus Torvalds return; 31171da177e4SLinus Torvalds } 31181da177e4SLinus Torvalds 3119074fe897SAndy Adamson /* 3120067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 3121074fe897SAndy Adamson */ 3122b607664eSTrond Myklebust static void 3123074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 3124074fe897SAndy Adamson { 3125bddfdbcdSChuck Lever struct xdr_buf *buf = resp->xdr->buf; 3126557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3127557ce264SAndy Adamson unsigned int base; 3128074fe897SAndy Adamson 3129557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 3130074fe897SAndy Adamson 3131085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 3132557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 3133557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 313453da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 313553da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 3136bf864a31SAndy Adamson 3137085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 3138085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 3139bf864a31SAndy Adamson return; 3140bf864a31SAndy Adamson } 3141085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 3142085def3aSJ. Bruce Fields 3143f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 3144f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 3145f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 3146d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 3147d3f03403SDan Carpenter __func__); 3148557ce264SAndy Adamson return; 3149074fe897SAndy Adamson } 3150074fe897SAndy Adamson 3151074fe897SAndy Adamson /* 3152abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 3153abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 3154abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 3155abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 3156abfabf8cSAndy Adamson * 3157074fe897SAndy Adamson */ 3158abfabf8cSAndy Adamson static __be32 3159abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 3160abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 3161074fe897SAndy Adamson { 3162abfabf8cSAndy Adamson struct nfsd4_op *op; 3163abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3164074fe897SAndy Adamson 3165abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 3166abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 3167abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 3168abfabf8cSAndy Adamson 3169085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 3170085def3aSJ. Bruce Fields return op->status; 3171085def3aSJ. Bruce Fields if (args->opcnt == 1) { 3172085def3aSJ. Bruce Fields /* 3173085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 3174085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 3175085def3aSJ. Bruce Fields * original: 3176085def3aSJ. Bruce Fields */ 3177085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 3178085def3aSJ. Bruce Fields } else { 3179abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 3180abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 3181abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 3182074fe897SAndy Adamson } 3183abfabf8cSAndy Adamson return op->status; 3184074fe897SAndy Adamson } 3185074fe897SAndy Adamson 3186074fe897SAndy Adamson /* 3187557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 3188557ce264SAndy Adamson * session values. 3189074fe897SAndy Adamson */ 31903ca2eb98SJ. Bruce Fields static __be32 3191bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 3192bf864a31SAndy Adamson struct nfsd4_sequence *seq) 3193074fe897SAndy Adamson { 3194557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3195bddfdbcdSChuck Lever struct xdr_stream *xdr = resp->xdr; 3196f5236013SJ. Bruce Fields __be32 *p; 3197074fe897SAndy Adamson __be32 status; 3198074fe897SAndy Adamson 3199557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 3200074fe897SAndy Adamson 3201abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 32020da7b19cSJ. Bruce Fields if (status) 3203abfabf8cSAndy Adamson return status; 3204074fe897SAndy Adamson 3205f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 3206f5236013SJ. Bruce Fields if (!p) { 3207f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 3208f5236013SJ. Bruce Fields return nfserr_serverfault; 3209f5236013SJ. Bruce Fields } 3210f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 3211f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 3212074fe897SAndy Adamson 3213557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 3214f5236013SJ. Bruce Fields return slot->sl_status; 3215074fe897SAndy Adamson } 3216074fe897SAndy Adamson 32170733d213SAndy Adamson /* 32180733d213SAndy Adamson * Set the exchange_id flags returned by the server. 32190733d213SAndy Adamson */ 32200733d213SAndy Adamson static void 32210733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 32220733d213SAndy Adamson { 32239cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 32249cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 32259cf514ccSChristoph Hellwig #else 32260733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 32279cf514ccSChristoph Hellwig #endif 32280733d213SAndy Adamson 32290733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 32300733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 32310733d213SAndy Adamson 32320733d213SAndy Adamson /* set the wire flags to return to client. */ 32330733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 32340733d213SAndy Adamson } 32350733d213SAndy Adamson 32364eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 32374eaea134SJ. Bruce Fields { 32384eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 32394eaea134SJ. Bruce Fields 32404eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 32414eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 32424eaea134SJ. Bruce Fields return true; 32434eaea134SJ. Bruce Fields } 32444eaea134SJ. Bruce Fields return false; 32454eaea134SJ. Bruce Fields } 32464eaea134SJ. Bruce Fields 3247631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 3248631fc9eaSJ. Bruce Fields { 32494eaea134SJ. Bruce Fields return client_has_openowners(clp) 325047e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 325147e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 325247e970beSKinglong Mee #endif 32536eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 3254e0639dc5SOlga Kornievskaia || !list_empty(&clp->cl_sessions) 3255e0639dc5SOlga Kornievskaia || !list_empty(&clp->async_copies); 3256631fc9eaSJ. Bruce Fields } 3257631fc9eaSJ. Bruce Fields 325879123444SJ. Bruce Fields static __be32 copy_impl_id(struct nfs4_client *clp, 325979123444SJ. Bruce Fields struct nfsd4_exchange_id *exid) 326079123444SJ. Bruce Fields { 326179123444SJ. Bruce Fields if (!exid->nii_domain.data) 326279123444SJ. Bruce Fields return 0; 326379123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_domain, &exid->nii_domain, GFP_KERNEL); 326479123444SJ. Bruce Fields if (!clp->cl_nii_domain.data) 326579123444SJ. Bruce Fields return nfserr_jukebox; 326679123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_name, &exid->nii_name, GFP_KERNEL); 326779123444SJ. Bruce Fields if (!clp->cl_nii_name.data) 326879123444SJ. Bruce Fields return nfserr_jukebox; 3269e29f4703SArnd Bergmann clp->cl_nii_time = exid->nii_time; 327079123444SJ. Bruce Fields return 0; 327179123444SJ. Bruce Fields } 327279123444SJ. Bruce Fields 3273b37ad28bSAl Viro __be32 3274eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3275eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3276069b6ad4SAndy Adamson { 3277eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 32783dbacee6STrond Myklebust struct nfs4_client *conf, *new; 32793dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 328057b7b43bSJ. Bruce Fields __be32 status; 3281363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 32820733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 3283363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 328483e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 3285c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 32860733d213SAndy Adamson 3287363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 32880733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 3289523ec6edSChuck Lever "ip_addr=%s flags %x, spa_how %u\n", 32900733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 3291363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 32920733d213SAndy Adamson 3293a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 32940733d213SAndy Adamson return nfserr_inval; 32950733d213SAndy Adamson 329650c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 329750c7b948SJ. Bruce Fields if (new == NULL) 329850c7b948SJ. Bruce Fields return nfserr_jukebox; 329979123444SJ. Bruce Fields status = copy_impl_id(new, exid); 330079123444SJ. Bruce Fields if (status) 330179123444SJ. Bruce Fields goto out_nolock; 330250c7b948SJ. Bruce Fields 33030733d213SAndy Adamson switch (exid->spa_how) { 330457266a6eSJ. Bruce Fields case SP4_MACH_CRED: 3305ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 3306ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 3307ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 3308ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 3309ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 3310ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 3311ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 3312ed941643SAndrew Elble 3313ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 3314ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 3315ed941643SAndrew Elble 1 << (OP_LOCKU) | 3316ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 3317ed941643SAndrew Elble 3318ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 3319ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 3320ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 332150c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 332250c7b948SJ. Bruce Fields status = nfserr_inval; 332350c7b948SJ. Bruce Fields goto out_nolock; 332450c7b948SJ. Bruce Fields } 3325920dd9bbSJ. Bruce Fields /* 3326920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 3327920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 3328920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 3329920dd9bbSJ. Bruce Fields */ 3330414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 3331414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 3332920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 3333920dd9bbSJ. Bruce Fields goto out_nolock; 3334920dd9bbSJ. Bruce Fields } 333550c7b948SJ. Bruce Fields new->cl_mach_cred = true; 333676c50eb7SGustavo A. R. Silva break; 33370733d213SAndy Adamson case SP4_NONE: 33380733d213SAndy Adamson break; 3339063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 3340063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 3341df561f66SGustavo A. R. Silva fallthrough; 33420733d213SAndy Adamson case SP4_SSV: 33438edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 33448edf4b02SKinglong Mee goto out_nolock; 33450733d213SAndy Adamson } 33460733d213SAndy Adamson 33472dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 33483dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3349382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 33500733d213SAndy Adamson if (conf) { 335183e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 335283e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 335383e08fd4SJ. Bruce Fields 3354136e658dSJ. Bruce Fields if (update) { 3355136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 33562dbb269dSJ. Bruce Fields status = nfserr_inval; 3357e203d506SJ. Bruce Fields goto out; 3358e203d506SJ. Bruce Fields } 3359dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 336057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 336157266a6eSJ. Bruce Fields goto out; 336257266a6eSJ. Bruce Fields } 33632dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 33640733d213SAndy Adamson status = nfserr_perm; 33650733d213SAndy Adamson goto out; 33660733d213SAndy Adamson } 33672dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 33680733d213SAndy Adamson status = nfserr_not_same; 33690733d213SAndy Adamson goto out; 33700733d213SAndy Adamson } 3371136e658dSJ. Bruce Fields /* case 6 */ 33720733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 3373e8f80c55SChuck Lever trace_nfsd_clid_confirmed_r(conf); 33740733d213SAndy Adamson goto out_copy; 33756ddbbbfeSMike Sager } 3376136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 3377631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 3378136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 337927787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 3380136e658dSJ. Bruce Fields goto out; 3381136e658dSJ. Bruce Fields } 3382b9831b59SJ. Bruce Fields goto out_new; 3383631fc9eaSJ. Bruce Fields } 3384136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 33850f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 3386e8f80c55SChuck Lever trace_nfsd_clid_confirmed_r(conf); 3387136e658dSJ. Bruce Fields goto out_copy; 3388136e658dSJ. Bruce Fields } 33892dbb269dSJ. Bruce Fields /* case 5, client reboot */ 3390744ea54cSChuck Lever trace_nfsd_clid_verf_mismatch(conf, rqstp, &verf); 33913dbacee6STrond Myklebust conf = NULL; 33920733d213SAndy Adamson goto out_new; 33930733d213SAndy Adamson } 33946ddbbbfeSMike Sager 33952dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 33960733d213SAndy Adamson status = nfserr_noent; 33970733d213SAndy Adamson goto out; 33980733d213SAndy Adamson } 33990733d213SAndy Adamson 3400a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 34012dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 34023dbacee6STrond Myklebust unhash_client_locked(unconf); 34030733d213SAndy Adamson 3404e8f80c55SChuck Lever /* case 1, new owner ID */ 3405e8f80c55SChuck Lever trace_nfsd_clid_fresh(new); 3406e8f80c55SChuck Lever 34070733d213SAndy Adamson out_new: 3408fd699b8aSJeff Layton if (conf) { 3409fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3410fd699b8aSJeff Layton if (status) 3411fd699b8aSJeff Layton goto out; 34122958d2eeSChuck Lever trace_nfsd_clid_replaced(&conf->cl_clientid); 3413fd699b8aSJeff Layton } 34144f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 3415ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 3416ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 34170733d213SAndy Adamson 3418ac55fdc4SJeff Layton add_to_unconfirmed(new); 34193dbacee6STrond Myklebust swap(new, conf); 34200733d213SAndy Adamson out_copy: 34215cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 34225cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 34230733d213SAndy Adamson 34245cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 34255cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 34260733d213SAndy Adamson 34270733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 34285cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 34290733d213SAndy Adamson status = nfs_ok; 34300733d213SAndy Adamson 34310733d213SAndy Adamson out: 34323dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 343350c7b948SJ. Bruce Fields out_nolock: 34345cc40fd7STrond Myklebust if (new) 34353dbacee6STrond Myklebust expire_client(new); 3436e8f80c55SChuck Lever if (unconf) { 3437e8f80c55SChuck Lever trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); 34383dbacee6STrond Myklebust expire_client(unconf); 3439e8f80c55SChuck Lever } 34400733d213SAndy Adamson return status; 3441069b6ad4SAndy Adamson } 3442069b6ad4SAndy Adamson 344357b7b43bSJ. Bruce Fields static __be32 344488e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 3445b85d4c01SBenny Halevy { 344688e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 344788e588d5SAndy Adamson slot_seqid); 3448b85d4c01SBenny Halevy 3449b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 345088e588d5SAndy Adamson if (slot_inuse) { 345188e588d5SAndy Adamson if (seqid == slot_seqid) 3452b85d4c01SBenny Halevy return nfserr_jukebox; 3453b85d4c01SBenny Halevy else 3454b85d4c01SBenny Halevy return nfserr_seq_misordered; 3455b85d4c01SBenny Halevy } 3456f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 345788e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 3458b85d4c01SBenny Halevy return nfs_ok; 345988e588d5SAndy Adamson if (seqid == slot_seqid) 3460b85d4c01SBenny Halevy return nfserr_replay_cache; 3461b85d4c01SBenny Halevy return nfserr_seq_misordered; 3462b85d4c01SBenny Halevy } 3463b85d4c01SBenny Halevy 346449557cc7SAndy Adamson /* 346549557cc7SAndy Adamson * Cache the create session result into the create session single DRC 346649557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 346749557cc7SAndy Adamson * Do this for solo or embedded create session operations. 346849557cc7SAndy Adamson */ 346949557cc7SAndy Adamson static void 347049557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 347157b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 347249557cc7SAndy Adamson { 347349557cc7SAndy Adamson slot->sl_status = nfserr; 347449557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 347549557cc7SAndy Adamson } 347649557cc7SAndy Adamson 347749557cc7SAndy Adamson static __be32 347849557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 347949557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 348049557cc7SAndy Adamson { 348149557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 348249557cc7SAndy Adamson return slot->sl_status; 348349557cc7SAndy Adamson } 348449557cc7SAndy Adamson 34851b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 34861b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 34871b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 34881b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 34891b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 34901b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 34911b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 34921b74c25bSMi Jinlong 34931b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 34941b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 34951b74c25bSMi Jinlong 1 + /* status */ \ 34961b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 34971b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 34981b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 34991b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 35001b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 35011b74c25bSMi Jinlong 350255c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 35031b74c25bSMi Jinlong { 350455c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 350555c760cfSJ. Bruce Fields 3506373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 3507373cd409SJ. Bruce Fields return nfserr_toosmall; 3508373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 3509373cd409SJ. Bruce Fields return nfserr_toosmall; 351055c760cfSJ. Bruce Fields ca->headerpadsz = 0; 351155c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 351255c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 351355c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 351455c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 351555c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 351655c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 351755c760cfSJ. Bruce Fields /* 351855c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 351955c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 352055c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 352155c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 352255c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 352355c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 35247f49fd5dSNeilBrown * Note that we always allow at least one slot, because our 35257f49fd5dSNeilBrown * accounting is soft and provides no guarantees either way. 352655c760cfSJ. Bruce Fields */ 35272030ca56SNeilBrown ca->maxreqs = nfsd4_get_drc_mem(ca, nn); 352855c760cfSJ. Bruce Fields 3529373cd409SJ. Bruce Fields return nfs_ok; 35301b74c25bSMi Jinlong } 35311b74c25bSMi Jinlong 35324500632fSChuck Lever /* 35334500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 35344500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 35354500632fSChuck Lever */ 35364500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 35374500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 35384500632fSChuck Lever 35394500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 35404500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 35414500632fSChuck Lever 35428a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 35434500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 35448a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 35454500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 35464500632fSChuck Lever sizeof(__be32)) 35478a891633SKinglong Mee 354806b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 354906b332a5SJ. Bruce Fields { 355006b332a5SJ. Bruce Fields ca->headerpadsz = 0; 355106b332a5SJ. Bruce Fields 35528a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 355306b332a5SJ. Bruce Fields return nfserr_toosmall; 35548a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 355506b332a5SJ. Bruce Fields return nfserr_toosmall; 355606b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 355706b332a5SJ. Bruce Fields if (ca->maxops < 2) 355806b332a5SJ. Bruce Fields return nfserr_toosmall; 355906b332a5SJ. Bruce Fields 356006b332a5SJ. Bruce Fields return nfs_ok; 3561069b6ad4SAndy Adamson } 3562069b6ad4SAndy Adamson 3563b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 3564b78724b7SJ. Bruce Fields { 3565b78724b7SJ. Bruce Fields switch (cbs->flavor) { 3566b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 3567b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 3568b78724b7SJ. Bruce Fields return nfs_ok; 3569b78724b7SJ. Bruce Fields default: 3570b78724b7SJ. Bruce Fields /* 3571b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 3572b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 3573b78724b7SJ. Bruce Fields * GSS. 3574b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 3575b78724b7SJ. Bruce Fields * client might think it can already handle: 3576b78724b7SJ. Bruce Fields */ 3577b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 3578b78724b7SJ. Bruce Fields } 3579b78724b7SJ. Bruce Fields } 3580b78724b7SJ. Bruce Fields 3581069b6ad4SAndy Adamson __be32 3582069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 3583eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 3584069b6ad4SAndy Adamson { 3585eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 3586363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 3587ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 3588d20c11d8SJeff Layton struct nfs4_client *old = NULL; 3589ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 359081f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 359149557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 359257b7b43bSJ. Bruce Fields __be32 status = 0; 35938daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3594ec6b5d7bSAndy Adamson 3595a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 3596a62573dcSMi Jinlong return nfserr_inval; 3597b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 3598b78724b7SJ. Bruce Fields if (status) 3599b78724b7SJ. Bruce Fields return status; 360055c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 3601373cd409SJ. Bruce Fields if (status) 3602373cd409SJ. Bruce Fields return status; 360306b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 360406b332a5SJ. Bruce Fields if (status) 3605f403e450SKinglong Mee goto out_release_drc_mem; 360681f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 360760810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 360855c760cfSJ. Bruce Fields if (!new) 360955c760cfSJ. Bruce Fields goto out_release_drc_mem; 361081f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 361181f0b2a4SJ. Bruce Fields if (!conn) 361281f0b2a4SJ. Bruce Fields goto out_free_session; 3613a62573dcSMi Jinlong 3614d20c11d8SJeff Layton spin_lock(&nn->client_lock); 36150a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 36168daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 361778389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3618ec6b5d7bSAndy Adamson 3619ec6b5d7bSAndy Adamson if (conf) { 362057266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3621dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 362257266a6eSJ. Bruce Fields goto out_free_conn; 362349557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 362449557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 3625f5e22bb6SKinglong Mee if (status) { 3626f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 362749557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 362881f0b2a4SJ. Bruce Fields goto out_free_conn; 3629ec6b5d7bSAndy Adamson } 3630ec6b5d7bSAndy Adamson } else if (unconf) { 363127787733SChuck Lever status = nfserr_clid_inuse; 3632ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 3633363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 363427787733SChuck Lever trace_nfsd_clid_cred_mismatch(unconf, rqstp); 363581f0b2a4SJ. Bruce Fields goto out_free_conn; 3636ec6b5d7bSAndy Adamson } 363757266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3638dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 363957266a6eSJ. Bruce Fields goto out_free_conn; 364049557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 364149557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 364238eb76a5SAndy Adamson if (status) { 364338eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 3644ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 364581f0b2a4SJ. Bruce Fields goto out_free_conn; 3646ec6b5d7bSAndy Adamson } 3647382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3648221a6876SJ. Bruce Fields if (old) { 3649d20c11d8SJeff Layton status = mark_client_expired_locked(old); 36507abea1e8SJeff Layton if (status) { 36517abea1e8SJeff Layton old = NULL; 3652221a6876SJ. Bruce Fields goto out_free_conn; 3653221a6876SJ. Bruce Fields } 36542958d2eeSChuck Lever trace_nfsd_clid_replaced(&old->cl_clientid); 36557abea1e8SJeff Layton } 36568f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 3657ec6b5d7bSAndy Adamson conf = unconf; 3658ec6b5d7bSAndy Adamson } else { 3659ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 366081f0b2a4SJ. Bruce Fields goto out_free_conn; 3661ec6b5d7bSAndy Adamson } 366281f0b2a4SJ. Bruce Fields status = nfs_ok; 36634ce85c8cSChuck Lever /* Persistent sessions are not supported */ 3664408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 36654ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 3666408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 3667408b79bcSJ. Bruce Fields 366881f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 3669d20c11d8SJeff Layton nfsd4_get_session_locked(new); 367081f0b2a4SJ. Bruce Fields 3671ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 3672ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 367386c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 367449557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 3675ec6b5d7bSAndy Adamson 3676d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 367749557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 3678d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3679934bd07fSJ. Bruce Fields if (conf == unconf) 3680934bd07fSJ. Bruce Fields fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); 3681d20c11d8SJeff Layton /* init connection and backchannel */ 3682d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 3683d20c11d8SJeff Layton nfsd4_put_session(new); 3684d20c11d8SJeff Layton if (old) 3685d20c11d8SJeff Layton expire_client(old); 3686ec6b5d7bSAndy Adamson return status; 368781f0b2a4SJ. Bruce Fields out_free_conn: 3688d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 368981f0b2a4SJ. Bruce Fields free_conn(conn); 3690d20c11d8SJeff Layton if (old) 3691d20c11d8SJeff Layton expire_client(old); 369281f0b2a4SJ. Bruce Fields out_free_session: 369381f0b2a4SJ. Bruce Fields __free_session(new); 369455c760cfSJ. Bruce Fields out_release_drc_mem: 369555c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 36961ca50792SJ. Bruce Fields return status; 3697069b6ad4SAndy Adamson } 3698069b6ad4SAndy Adamson 36991d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 37001d1bc8f2SJ. Bruce Fields { 37011d1bc8f2SJ. Bruce Fields switch (*dir) { 37021d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 37031d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 37041d1bc8f2SJ. Bruce Fields return nfs_ok; 37051d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 37061d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 37071d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 37081d1bc8f2SJ. Bruce Fields return nfs_ok; 3709fc5fc5d7Szhengbin } 37101d1bc8f2SJ. Bruce Fields return nfserr_inval; 37111d1bc8f2SJ. Bruce Fields } 37121d1bc8f2SJ. Bruce Fields 3713eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 3714eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3715eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3716cb73a9f4SJ. Bruce Fields { 3717eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 3718cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 3719c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3720b78724b7SJ. Bruce Fields __be32 status; 3721cb73a9f4SJ. Bruce Fields 3722b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 3723b78724b7SJ. Bruce Fields if (status) 3724b78724b7SJ. Bruce Fields return status; 3725c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3726cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 3727cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 3728c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3729cb73a9f4SJ. Bruce Fields 3730cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 3731cb73a9f4SJ. Bruce Fields 3732cb73a9f4SJ. Bruce Fields return nfs_ok; 3733cb73a9f4SJ. Bruce Fields } 3734cb73a9f4SJ. Bruce Fields 3735c2d715a1SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3736c2d715a1SJ. Bruce Fields { 3737c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3738c2d715a1SJ. Bruce Fields 3739c2d715a1SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3740c2d715a1SJ. Bruce Fields if (c->cn_xprt == xpt) { 3741c2d715a1SJ. Bruce Fields return c; 3742c2d715a1SJ. Bruce Fields } 3743c2d715a1SJ. Bruce Fields } 3744c2d715a1SJ. Bruce Fields return NULL; 3745c2d715a1SJ. Bruce Fields } 3746c2d715a1SJ. Bruce Fields 3747c2d715a1SJ. Bruce Fields static __be32 nfsd4_match_existing_connection(struct svc_rqst *rqst, 374802579b2fSDai Ngo struct nfsd4_session *session, u32 req, struct nfsd4_conn **conn) 3749c2d715a1SJ. Bruce Fields { 3750c2d715a1SJ. Bruce Fields struct nfs4_client *clp = session->se_client; 3751c2d715a1SJ. Bruce Fields struct svc_xprt *xpt = rqst->rq_xprt; 3752c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3753c2d715a1SJ. Bruce Fields __be32 status; 3754c2d715a1SJ. Bruce Fields 3755c2d715a1SJ. Bruce Fields /* Following the last paragraph of RFC 5661 Section 18.34.3: */ 3756c2d715a1SJ. Bruce Fields spin_lock(&clp->cl_lock); 3757c2d715a1SJ. Bruce Fields c = __nfsd4_find_conn(xpt, session); 3758c2d715a1SJ. Bruce Fields if (!c) 3759c2d715a1SJ. Bruce Fields status = nfserr_noent; 3760c2d715a1SJ. Bruce Fields else if (req == c->cn_flags) 3761c2d715a1SJ. Bruce Fields status = nfs_ok; 3762c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_FORE_OR_BOTH && 3763c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_BACK) 3764c2d715a1SJ. Bruce Fields status = nfs_ok; 3765c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_BACK_OR_BOTH && 3766c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_FORE) 3767c2d715a1SJ. Bruce Fields status = nfs_ok; 3768c2d715a1SJ. Bruce Fields else 3769c2d715a1SJ. Bruce Fields status = nfserr_inval; 3770c2d715a1SJ. Bruce Fields spin_unlock(&clp->cl_lock); 377102579b2fSDai Ngo if (status == nfs_ok && conn) 377202579b2fSDai Ngo *conn = c; 3773c2d715a1SJ. Bruce Fields return status; 3774c2d715a1SJ. Bruce Fields } 3775c2d715a1SJ. Bruce Fields 37761d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 37771d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 3778eb69853dSChristoph Hellwig union nfsd4_op_u *u) 37791d1bc8f2SJ. Bruce Fields { 3780eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 37811d1bc8f2SJ. Bruce Fields __be32 status; 37823ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 37834f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 3784d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3785d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 37861d1bc8f2SJ. Bruce Fields 37871d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 37881d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 3789c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3790d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 3791c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 37924f6e6c17SJ. Bruce Fields if (!session) 3793d4e19e70STrond Myklebust goto out_no_session; 379457266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3795dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 379657266a6eSJ. Bruce Fields goto out; 379702579b2fSDai Ngo status = nfsd4_match_existing_connection(rqstp, session, 379802579b2fSDai Ngo bcts->dir, &conn); 379902579b2fSDai Ngo if (status == nfs_ok) { 380002579b2fSDai Ngo if (bcts->dir == NFS4_CDFC4_FORE_OR_BOTH || 380102579b2fSDai Ngo bcts->dir == NFS4_CDFC4_BACK) 380202579b2fSDai Ngo conn->cn_flags |= NFS4_CDFC4_BACK; 380302579b2fSDai Ngo nfsd4_probe_callback(session->se_client); 380402579b2fSDai Ngo goto out; 380502579b2fSDai Ngo } 380602579b2fSDai Ngo if (status == nfserr_inval) 3807c2d715a1SJ. Bruce Fields goto out; 38081d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 38093ba63671SJ. Bruce Fields if (status) 38104f6e6c17SJ. Bruce Fields goto out; 38113ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 38124f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 38133ba63671SJ. Bruce Fields if (!conn) 38144f6e6c17SJ. Bruce Fields goto out; 38154f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 38164f6e6c17SJ. Bruce Fields status = nfs_ok; 38174f6e6c17SJ. Bruce Fields out: 3818d4e19e70STrond Myklebust nfsd4_put_session(session); 3819d4e19e70STrond Myklebust out_no_session: 38204f6e6c17SJ. Bruce Fields return status; 38211d1bc8f2SJ. Bruce Fields } 38221d1bc8f2SJ. Bruce Fields 3823665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 38245d4cec2fSJ. Bruce Fields { 3825665d5072SJ. Bruce Fields if (!cstate->session) 382651d87bc2SFengguang Wu return false; 3827665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 38285d4cec2fSJ. Bruce Fields } 38295d4cec2fSJ. Bruce Fields 3830069b6ad4SAndy Adamson __be32 3831eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 3832eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3833069b6ad4SAndy Adamson { 3834ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 3835e10e0cfcSBenny Halevy struct nfsd4_session *ses; 3836abcdff09SJ. Bruce Fields __be32 status; 3837f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 3838d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 3839d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3840e10e0cfcSBenny Halevy 3841abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 3842ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 384357716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 3844abcdff09SJ. Bruce Fields goto out; 3845f0f51f5cSJ. Bruce Fields ref_held_by_me++; 384657716355SJ. Bruce Fields } 3847ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 3848c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3849ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 3850abcdff09SJ. Bruce Fields if (!ses) 3851abcdff09SJ. Bruce Fields goto out_client_lock; 385257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3853dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 3854d4e19e70STrond Myklebust goto out_put_session; 3855f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 385666b2b9b2SJ. Bruce Fields if (status) 3857f0f51f5cSJ. Bruce Fields goto out_put_session; 3858e10e0cfcSBenny Halevy unhash_session(ses); 3859c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3860e10e0cfcSBenny Halevy 386184f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 386219cf5c02SJ. Bruce Fields 3863c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3864e10e0cfcSBenny Halevy status = nfs_ok; 3865f0f51f5cSJ. Bruce Fields out_put_session: 3866d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3867abcdff09SJ. Bruce Fields out_client_lock: 3868abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3869e10e0cfcSBenny Halevy out: 3870e10e0cfcSBenny Halevy return status; 3871069b6ad4SAndy Adamson } 3872069b6ad4SAndy Adamson 387357266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3874328ead28SJ. Bruce Fields { 3875328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3876a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 387757266a6eSJ. Bruce Fields __be32 status = nfs_ok; 387821b75b01SJ. Bruce Fields int ret; 3879328ead28SJ. Bruce Fields 3880328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3881a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 388257266a6eSJ. Bruce Fields if (c) 388357266a6eSJ. Bruce Fields goto out_free; 388457266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 388557266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 388657266a6eSJ. Bruce Fields goto out_free; 3887328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3888328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 388921b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 389021b75b01SJ. Bruce Fields if (ret) 389121b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 389221b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 389357266a6eSJ. Bruce Fields return nfs_ok; 389457266a6eSJ. Bruce Fields out_free: 389557266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 389657266a6eSJ. Bruce Fields free_conn(new); 389757266a6eSJ. Bruce Fields return status; 3898328ead28SJ. Bruce Fields } 3899328ead28SJ. Bruce Fields 3900868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3901868b89c3SMi Jinlong { 3902868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3903868b89c3SMi Jinlong 3904868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3905868b89c3SMi Jinlong } 3906868b89c3SMi Jinlong 3907ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3908ae82a8d0SMi Jinlong struct nfsd4_session *session) 3909ae82a8d0SMi Jinlong { 3910ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3911ae82a8d0SMi Jinlong 3912ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3913ae82a8d0SMi Jinlong } 3914ae82a8d0SMi Jinlong 391553da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 391653da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 391753da6a53SJ. Bruce Fields { 391853da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 391953da6a53SJ. Bruce Fields 392053da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 392153da6a53SJ. Bruce Fields (bool)seq->cachethis) 392253da6a53SJ. Bruce Fields return false; 392353da6a53SJ. Bruce Fields /* 39246e73e92bSScott Mayhew * If there's an error then the reply can have fewer ops than 39256e73e92bSScott Mayhew * the call. 392653da6a53SJ. Bruce Fields */ 39276e73e92bSScott Mayhew if (slot->sl_opcnt < argp->opcnt && !slot->sl_status) 39286e73e92bSScott Mayhew return false; 39296e73e92bSScott Mayhew /* 39306e73e92bSScott Mayhew * But if we cached a reply with *more* ops than the call you're 39316e73e92bSScott Mayhew * sending us now, then this new call is clearly not really a 39326e73e92bSScott Mayhew * replay of the old one: 39336e73e92bSScott Mayhew */ 39346e73e92bSScott Mayhew if (slot->sl_opcnt > argp->opcnt) 393553da6a53SJ. Bruce Fields return false; 393653da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 393753da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 393853da6a53SJ. Bruce Fields return false; 393953da6a53SJ. Bruce Fields /* 394053da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 394153da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 394253da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 394353da6a53SJ. Bruce Fields * the reply), so we don't bother. 394453da6a53SJ. Bruce Fields */ 394553da6a53SJ. Bruce Fields return true; 394653da6a53SJ. Bruce Fields } 394753da6a53SJ. Bruce Fields 3948069b6ad4SAndy Adamson __be32 3949eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3950eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3951069b6ad4SAndy Adamson { 3952eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3953f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 3954bddfdbcdSChuck Lever struct xdr_stream *xdr = resp->xdr; 3955b85d4c01SBenny Halevy struct nfsd4_session *session; 3956221a6876SJ. Bruce Fields struct nfs4_client *clp; 3957b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3958a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 395957b7b43bSJ. Bruce Fields __be32 status; 396047ee5298SJ. Bruce Fields int buflen; 3961d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3962d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3963b85d4c01SBenny Halevy 3964f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3965f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3966f9bb94c4SAndy Adamson 3967a663bdd8SJ. Bruce Fields /* 3968a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3969a663bdd8SJ. Bruce Fields * below. 3970a663bdd8SJ. Bruce Fields */ 3971a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3972a663bdd8SJ. Bruce Fields if (!conn) 3973a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3974a663bdd8SJ. Bruce Fields 3975c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3976d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3977b85d4c01SBenny Halevy if (!session) 3978221a6876SJ. Bruce Fields goto out_no_session; 3979221a6876SJ. Bruce Fields clp = session->se_client; 3980b85d4c01SBenny Halevy 3981868b89c3SMi Jinlong status = nfserr_too_many_ops; 3982868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 398366b2b9b2SJ. Bruce Fields goto out_put_session; 3984868b89c3SMi Jinlong 3985ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3986ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 398766b2b9b2SJ. Bruce Fields goto out_put_session; 3988ae82a8d0SMi Jinlong 3989b85d4c01SBenny Halevy status = nfserr_badslot; 39906c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 399166b2b9b2SJ. Bruce Fields goto out_put_session; 3992b85d4c01SBenny Halevy 3993557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3994b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3995b85d4c01SBenny Halevy 3996a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3997a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3998a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3999a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 4000a8dfdaebSAndy Adamson 400173e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 400273e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 4003b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 4004bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 4005bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 400666b2b9b2SJ. Bruce Fields goto out_put_session; 400753da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 400853da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 400953da6a53SJ. Bruce Fields goto out_put_session; 4010b85d4c01SBenny Halevy cstate->slot = slot; 4011b85d4c01SBenny Halevy cstate->session = session; 40124b24ca7dSJeff Layton cstate->clp = clp; 4013da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 4014557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 4015bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 4016da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 4017aaf84eb9SBenny Halevy goto out; 4018b85d4c01SBenny Halevy } 4019b85d4c01SBenny Halevy if (status) 402066b2b9b2SJ. Bruce Fields goto out_put_session; 4021b85d4c01SBenny Halevy 402257266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 4023a663bdd8SJ. Bruce Fields conn = NULL; 402457266a6eSJ. Bruce Fields if (status) 402557266a6eSJ. Bruce Fields goto out_put_session; 4026328ead28SJ. Bruce Fields 402747ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 402847ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 402947ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 403047ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 403147ee5298SJ. Bruce Fields nfserr_rep_too_big; 4032a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 403347ee5298SJ. Bruce Fields goto out_put_session; 403432aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 403547ee5298SJ. Bruce Fields 403647ee5298SJ. Bruce Fields status = nfs_ok; 4037b85d4c01SBenny Halevy /* Success! bump slot seqid */ 4038b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 4039bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 404073e79482SJ. Bruce Fields if (seq->cachethis) 404173e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 4042bf5c43c8SJ. Bruce Fields else 4043bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 4044b85d4c01SBenny Halevy 4045b85d4c01SBenny Halevy cstate->slot = slot; 4046b85d4c01SBenny Halevy cstate->session = session; 40474b24ca7dSJeff Layton cstate->clp = clp; 4048b85d4c01SBenny Halevy 4049b85d4c01SBenny Halevy out: 40505423732aSBenny Halevy switch (clp->cl_cb_state) { 40515423732aSBenny Halevy case NFSD4_CB_DOWN: 4052fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 40535423732aSBenny Halevy break; 40545423732aSBenny Halevy case NFSD4_CB_FAULT: 4055fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 40565423732aSBenny Halevy break; 4057fc0c3dd1SBenny Halevy default: 4058fc0c3dd1SBenny Halevy seq->status_flags = 0; 40595423732aSBenny Halevy } 40603bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 40613bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 4062221a6876SJ. Bruce Fields out_no_session: 40633f42d2c4SKinglong Mee if (conn) 40643f42d2c4SKinglong Mee free_conn(conn); 4065c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 4066b85d4c01SBenny Halevy return status; 406766b2b9b2SJ. Bruce Fields out_put_session: 4068d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 4069221a6876SJ. Bruce Fields goto out_no_session; 4070069b6ad4SAndy Adamson } 4071069b6ad4SAndy Adamson 4072b607664eSTrond Myklebust void 4073b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 4074b607664eSTrond Myklebust { 4075b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 4076b607664eSTrond Myklebust 4077b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 4078b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 4079b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 4080b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 4081b607664eSTrond Myklebust } 4082d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 4083b607664eSTrond Myklebust nfsd4_put_session(cs->session); 40844b24ca7dSJeff Layton } else if (cs->clp) 40854b24ca7dSJeff Layton put_client_renew(cs->clp); 4086b607664eSTrond Myklebust } 4087b607664eSTrond Myklebust 4088345c2842SMi Jinlong __be32 4089eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 4090eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 4091eb69853dSChristoph Hellwig union nfsd4_op_u *u) 4092345c2842SMi Jinlong { 4093eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 40946b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 40956b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 409657b7b43bSJ. Bruce Fields __be32 status = 0; 40978daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 4098345c2842SMi Jinlong 40996b10ad19STrond Myklebust spin_lock(&nn->client_lock); 41000a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 41018daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 410278389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 4103345c2842SMi Jinlong 4104345c2842SMi Jinlong if (conf) { 4105c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 4106345c2842SMi Jinlong status = nfserr_clientid_busy; 4107345c2842SMi Jinlong goto out; 4108345c2842SMi Jinlong } 4109fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 4110fd699b8aSJeff Layton if (status) 4111fd699b8aSJeff Layton goto out; 41126b10ad19STrond Myklebust clp = conf; 4113345c2842SMi Jinlong } else if (unconf) 4114345c2842SMi Jinlong clp = unconf; 4115345c2842SMi Jinlong else { 4116345c2842SMi Jinlong status = nfserr_stale_clientid; 4117345c2842SMi Jinlong goto out; 4118345c2842SMi Jinlong } 4119dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 41206b10ad19STrond Myklebust clp = NULL; 412157266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 412257266a6eSJ. Bruce Fields goto out; 412357266a6eSJ. Bruce Fields } 4124c41a9b7aSChuck Lever trace_nfsd_clid_destroyed(&clp->cl_clientid); 41256b10ad19STrond Myklebust unhash_client_locked(clp); 4126345c2842SMi Jinlong out: 41276b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 41286b10ad19STrond Myklebust if (clp) 41296b10ad19STrond Myklebust expire_client(clp); 4130345c2842SMi Jinlong return status; 4131345c2842SMi Jinlong } 4132345c2842SMi Jinlong 4133069b6ad4SAndy Adamson __be32 4134eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 4135eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 41364dc6ec00SJ. Bruce Fields { 4137eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 4138ec59659bSJ. Bruce Fields struct nfs4_client *clp = cstate->clp; 413957b7b43bSJ. Bruce Fields __be32 status = 0; 4140bcecf1ccSMi Jinlong 41414dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 41424dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 41434dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 41444dc6ec00SJ. Bruce Fields /* 41454dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 41464dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 41474dc6ec00SJ. Bruce Fields */ 41484dc6ec00SJ. Bruce Fields return nfs_ok; 41494dc6ec00SJ. Bruce Fields } 4150bcecf1ccSMi Jinlong 4151bcecf1ccSMi Jinlong status = nfserr_complete_already; 4152ec59659bSJ. Bruce Fields if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) 4153bcecf1ccSMi Jinlong goto out; 4154bcecf1ccSMi Jinlong 4155bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 4156ec59659bSJ. Bruce Fields if (is_client_expired(clp)) 41574dc6ec00SJ. Bruce Fields /* 41584dc6ec00SJ. Bruce Fields * The following error isn't really legal. 41594dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 41604dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 41614dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 41624dc6ec00SJ. Bruce Fields * client. 41634dc6ec00SJ. Bruce Fields */ 4164bcecf1ccSMi Jinlong goto out; 4165bcecf1ccSMi Jinlong 4166bcecf1ccSMi Jinlong status = nfs_ok; 4167cee8aa07SChuck Lever trace_nfsd_clid_reclaim_complete(&clp->cl_clientid); 4168ec59659bSJ. Bruce Fields nfsd4_client_record_create(clp); 4169ec59659bSJ. Bruce Fields inc_reclaim_complete(clp); 4170bcecf1ccSMi Jinlong out: 4171bcecf1ccSMi Jinlong return status; 41724dc6ec00SJ. Bruce Fields } 41734dc6ec00SJ. Bruce Fields 41744dc6ec00SJ. Bruce Fields __be32 4175b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4176eb69853dSChristoph Hellwig union nfsd4_op_u *u) 41771da177e4SLinus Torvalds { 4178eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 4179a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 41801da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 41813dbacee6STrond Myklebust struct nfs4_client *conf, *new; 41823dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 4183b37ad28bSAl Viro __be32 status; 4184c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 4185a55370a3SNeilBrown 41865cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 41875cc40fd7STrond Myklebust if (new == NULL) 41885cc40fd7STrond Myklebust return nfserr_jukebox; 41893dbacee6STrond Myklebust spin_lock(&nn->client_lock); 4190382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 41912b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 41921da177e4SLinus Torvalds status = nfserr_clid_inuse; 4193e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 4194e203d506SJ. Bruce Fields goto out; 4195026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 419627787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 41971da177e4SLinus Torvalds goto out; 41981da177e4SLinus Torvalds } 41991da177e4SLinus Torvalds } 4200a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 42011da177e4SLinus Torvalds if (unconf) 42023dbacee6STrond Myklebust unhash_client_locked(unconf); 4203744ea54cSChuck Lever if (conf) { 4204744ea54cSChuck Lever if (same_verf(&conf->cl_verifier, &clverifier)) { 42051da177e4SLinus Torvalds copy_clid(new, conf); 420641eb1670SKinglong Mee gen_confirm(new, nn); 4207744ea54cSChuck Lever } else 4208744ea54cSChuck Lever trace_nfsd_clid_verf_mismatch(conf, rqstp, 4209744ea54cSChuck Lever &clverifier); 4210237f91c8SChuck Lever } else 4211237f91c8SChuck Lever trace_nfsd_clid_fresh(new); 42128323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 42136f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 4214ac55fdc4SJeff Layton add_to_unconfirmed(new); 42151da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 42161da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 42171da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 42185cc40fd7STrond Myklebust new = NULL; 42191da177e4SLinus Torvalds status = nfs_ok; 42201da177e4SLinus Torvalds out: 42213dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 42225cc40fd7STrond Myklebust if (new) 42235cc40fd7STrond Myklebust free_client(new); 4224237f91c8SChuck Lever if (unconf) { 4225237f91c8SChuck Lever trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); 42263dbacee6STrond Myklebust expire_client(unconf); 4227237f91c8SChuck Lever } 42281da177e4SLinus Torvalds return status; 42291da177e4SLinus Torvalds } 42301da177e4SLinus Torvalds 4231b37ad28bSAl Viro __be32 4232b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 4233b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 4234eb69853dSChristoph Hellwig union nfsd4_op_u *u) 42351da177e4SLinus Torvalds { 4236eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 4237eb69853dSChristoph Hellwig &u->setclientid_confirm; 423821ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 4239d20c11d8SJeff Layton struct nfs4_client *old = NULL; 42401da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 42411da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 4242b37ad28bSAl Viro __be32 status; 42437f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 42441da177e4SLinus Torvalds 42452c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 42461da177e4SLinus Torvalds return nfserr_stale_clientid; 424721ab45a4SNeilBrown 4248d20c11d8SJeff Layton spin_lock(&nn->client_lock); 42498daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 42500a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 4251a186e767SJ. Bruce Fields /* 42528695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 42538695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 4254f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 4255f984a7ceSJ. Bruce Fields * 4256f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 4257a186e767SJ. Bruce Fields */ 4258f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 425927787733SChuck Lever if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { 426027787733SChuck Lever trace_nfsd_clid_cred_mismatch(unconf, rqstp); 42618695b90aSJ. Bruce Fields goto out; 426227787733SChuck Lever } 426327787733SChuck Lever if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 426427787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 42658695b90aSJ. Bruce Fields goto out; 426627787733SChuck Lever } 426790d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 42687d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 426990d700b7SJ. Bruce Fields status = nfs_ok; 4270237f91c8SChuck Lever } else 427190d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 427290d700b7SJ. Bruce Fields goto out; 427390d700b7SJ. Bruce Fields } 427490d700b7SJ. Bruce Fields status = nfs_ok; 4275237f91c8SChuck Lever if (conf) { 4276d20c11d8SJeff Layton old = unconf; 4277d20c11d8SJeff Layton unhash_client_locked(old); 42785a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 4279237f91c8SChuck Lever } else { 4280d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 4281d20c11d8SJeff Layton if (old) { 42822b634821SJ. Bruce Fields status = nfserr_clid_inuse; 42832b634821SJ. Bruce Fields if (client_has_state(old) 42842b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 4285ab451ea9SDai Ngo &old->cl_cred)) { 4286ab451ea9SDai Ngo old = NULL; 42872b634821SJ. Bruce Fields goto out; 4288ab451ea9SDai Ngo } 4289d20c11d8SJeff Layton status = mark_client_expired_locked(old); 42907abea1e8SJeff Layton if (status) { 42917abea1e8SJeff Layton old = NULL; 4292221a6876SJ. Bruce Fields goto out; 4293221a6876SJ. Bruce Fields } 42942958d2eeSChuck Lever trace_nfsd_clid_replaced(&old->cl_clientid); 42957abea1e8SJeff Layton } 42961da177e4SLinus Torvalds move_to_confirmed(unconf); 4297d20c11d8SJeff Layton conf = unconf; 429808e8987cSNeilBrown } 4299d20c11d8SJeff Layton get_client_locked(conf); 4300d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4301934bd07fSJ. Bruce Fields if (conf == unconf) 4302934bd07fSJ. Bruce Fields fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); 4303d20c11d8SJeff Layton nfsd4_probe_callback(conf); 4304d20c11d8SJeff Layton spin_lock(&nn->client_lock); 4305d20c11d8SJeff Layton put_client_renew_locked(conf); 43061da177e4SLinus Torvalds out: 4307d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4308d20c11d8SJeff Layton if (old) 4309d20c11d8SJeff Layton expire_client(old); 43101da177e4SLinus Torvalds return status; 43111da177e4SLinus Torvalds } 43121da177e4SLinus Torvalds 431332513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 43141da177e4SLinus Torvalds { 431532513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 431632513b40SJ. Bruce Fields } 431732513b40SJ. Bruce Fields 431832513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 4319950e0118STrond Myklebust 432081a21fa3SChuck Lever static void nfsd4_file_init(const struct svc_fh *fh, struct nfs4_file *fp) 432181a21fa3SChuck Lever { 4322818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 43231d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 43248beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 43258beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 43268287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 4327f9b60e22SJ. Bruce Fields fh_copy_shallow(&fp->fi_fhandle, &fh->fh_handle); 43280c637be8SJeff Layton fp->fi_deleg_file = NULL; 432947f9940cSMeelap Shah fp->fi_had_conflict = false; 4330baeb4ff0SJeff Layton fp->fi_share_deny = 0; 4331f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 4332f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 4333a0ce4837SJ. Bruce Fields fp->fi_aliased = false; 4334a0ce4837SJ. Bruce Fields fp->fi_inode = d_inode(fh->fh_dentry); 43359cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 43369cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 4337c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 43389cf514ccSChristoph Hellwig #endif 43391da177e4SLinus Torvalds } 43401da177e4SLinus Torvalds 4341e8ff2a84SJ. Bruce Fields void 4342e60d4398SNeilBrown nfsd4_free_slabs(void) 4343e60d4398SNeilBrown { 43449258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4345abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 4346abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4347abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4348abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4349abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 43509258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 4351e60d4398SNeilBrown } 43521da177e4SLinus Torvalds 435372083396SBryan Schumaker int 43541da177e4SLinus Torvalds nfsd4_init_slabs(void) 43551da177e4SLinus Torvalds { 43569258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 43579258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 43589258a2d5SJeff Layton if (client_slab == NULL) 43599258a2d5SJeff Layton goto out; 4360fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 4361fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 4362fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 43639258a2d5SJeff Layton goto out_free_client_slab; 4364fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 43653c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 4366fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 4367abf1135bSChristoph Hellwig goto out_free_openowner_slab; 4368e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 436920c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 4370e60d4398SNeilBrown if (file_slab == NULL) 4371abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 43725ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 4373dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 43745ac049acSNeilBrown if (stateid_slab == NULL) 4375abf1135bSChristoph Hellwig goto out_free_file_slab; 43765b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 437720c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 43785b2d21c1SNeilBrown if (deleg_slab == NULL) 4379abf1135bSChristoph Hellwig goto out_free_stateid_slab; 43808287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 43818287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 43828287f009SSachin Bhamare if (odstate_slab == NULL) 43838287f009SSachin Bhamare goto out_free_deleg_slab; 4384e60d4398SNeilBrown return 0; 4385abf1135bSChristoph Hellwig 43868287f009SSachin Bhamare out_free_deleg_slab: 43878287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 4388abf1135bSChristoph Hellwig out_free_stateid_slab: 4389abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4390abf1135bSChristoph Hellwig out_free_file_slab: 4391abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4392abf1135bSChristoph Hellwig out_free_lockowner_slab: 4393abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4394abf1135bSChristoph Hellwig out_free_openowner_slab: 4395abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 43969258a2d5SJeff Layton out_free_client_slab: 43979258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4398abf1135bSChristoph Hellwig out: 43991da177e4SLinus Torvalds return -ENOMEM; 44001da177e4SLinus Torvalds } 44011da177e4SLinus Torvalds 44027746b32fSDai Ngo static unsigned long 4403a1049eb4SDai Ngo nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) 44047746b32fSDai Ngo { 4405*44df6f43SDai Ngo int count; 44067746b32fSDai Ngo struct nfsd_net *nn = container_of(shrink, 44077746b32fSDai Ngo struct nfsd_net, nfsd_client_shrinker); 44087746b32fSDai Ngo 4409*44df6f43SDai Ngo count = atomic_read(&nn->nfsd_courtesy_clients); 4410*44df6f43SDai Ngo if (!count) 4411*44df6f43SDai Ngo count = atomic_long_read(&num_delegations); 4412*44df6f43SDai Ngo if (count) 44137746b32fSDai Ngo mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0); 4414*44df6f43SDai Ngo return (unsigned long)count; 44157746b32fSDai Ngo } 44167746b32fSDai Ngo 44177746b32fSDai Ngo static unsigned long 4418a1049eb4SDai Ngo nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc) 44197746b32fSDai Ngo { 44207746b32fSDai Ngo return SHRINK_STOP; 44217746b32fSDai Ngo } 44227746b32fSDai Ngo 44237746b32fSDai Ngo int 44247746b32fSDai Ngo nfsd4_init_leases_net(struct nfsd_net *nn) 44256867137eSDai Ngo { 44264271c2c0SDai Ngo struct sysinfo si; 44274271c2c0SDai Ngo u64 max_clients; 44284271c2c0SDai Ngo 44296867137eSDai Ngo nn->nfsd4_lease = 90; /* default lease time */ 44306867137eSDai Ngo nn->nfsd4_grace = 90; 44316867137eSDai Ngo nn->somebody_reclaimed = false; 44326867137eSDai Ngo nn->track_reclaim_completes = false; 4433a251c17aSJason A. Donenfeld nn->clverifier_counter = get_random_u32(); 4434a251c17aSJason A. Donenfeld nn->clientid_base = get_random_u32(); 44356867137eSDai Ngo nn->clientid_counter = nn->clientid_base + 1; 44366867137eSDai Ngo nn->s2s_cp_cl_id = nn->clientid_counter++; 44370926c395SDai Ngo 44380926c395SDai Ngo atomic_set(&nn->nfs4_client_count, 0); 44394271c2c0SDai Ngo si_meminfo(&si); 44404271c2c0SDai Ngo max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024); 44414271c2c0SDai Ngo max_clients *= NFS4_CLIENTS_PER_GB; 44424271c2c0SDai Ngo nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); 44433a4ea23dSDai Ngo 44443a4ea23dSDai Ngo atomic_set(&nn->nfsd_courtesy_clients, 0); 4445a1049eb4SDai Ngo nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan; 4446a1049eb4SDai Ngo nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count; 44477746b32fSDai Ngo nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS; 44487746b32fSDai Ngo return register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client"); 44497746b32fSDai Ngo } 44507746b32fSDai Ngo 44517746b32fSDai Ngo void 44527746b32fSDai Ngo nfsd4_leases_net_shutdown(struct nfsd_net *nn) 44537746b32fSDai Ngo { 44547746b32fSDai Ngo unregister_shrinker(&nn->nfsd_client_shrinker); 44556867137eSDai Ngo } 44566867137eSDai Ngo 4457ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 4458ff194bd9SJ. Bruce Fields { 4459ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 4460ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 4461ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 446258fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 446358fb12e6SJeff Layton } 446458fb12e6SJeff Layton 446558fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 446658fb12e6SJeff Layton struct nfs4_stateowner *so) 446758fb12e6SJeff Layton { 446858fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 446958fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 4470b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 447158fb12e6SJeff Layton } 447258fb12e6SJeff Layton } 447358fb12e6SJeff Layton 447458fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 447558fb12e6SJeff Layton { 447658fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 447758fb12e6SJeff Layton 447858fb12e6SJeff Layton if (so != NULL) { 447958fb12e6SJeff Layton cstate->replay_owner = NULL; 448058fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 448158fb12e6SJeff Layton nfs4_put_stateowner(so); 448258fb12e6SJeff Layton } 4483ff194bd9SJ. Bruce Fields } 4484ff194bd9SJ. Bruce Fields 4485fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 44861da177e4SLinus Torvalds { 44871da177e4SLinus Torvalds struct nfs4_stateowner *sop; 44881da177e4SLinus Torvalds 4489fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 4490ff194bd9SJ. Bruce Fields if (!sop) 4491ff194bd9SJ. Bruce Fields return NULL; 4492ff194bd9SJ. Bruce Fields 44936f4859b8SJ. Bruce Fields xdr_netobj_dup(&sop->so_owner, owner, GFP_KERNEL); 4494ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 4495fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 4496ff194bd9SJ. Bruce Fields return NULL; 4497ff194bd9SJ. Bruce Fields } 4498ff194bd9SJ. Bruce Fields 4499ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 4500ff194bd9SJ. Bruce Fields sop->so_client = clp; 4501ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 45026b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 45031da177e4SLinus Torvalds return sop; 45041da177e4SLinus Torvalds } 4505ff194bd9SJ. Bruce Fields 4506fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 4507ff194bd9SJ. Bruce Fields { 4508d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 45099b531137SStanislav Kinsbursky 4510d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 4511d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 4512fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 45131da177e4SLinus Torvalds } 45141da177e4SLinus Torvalds 45158f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 45168f4b54c5SJeff Layton { 4517d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 45188f4b54c5SJeff Layton } 45198f4b54c5SJeff Layton 45206b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 45216b180f0bSJeff Layton { 45226b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 45236b180f0bSJeff Layton 45246b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 45256b180f0bSJeff Layton } 45266b180f0bSJeff Layton 45276b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 45288f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 45296b180f0bSJeff Layton .so_free = nfs4_free_openowner, 45306b180f0bSJeff Layton }; 45316b180f0bSJeff Layton 45327fc0564eSAndrew Elble static struct nfs4_ol_stateid * 45337fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 45347fc0564eSAndrew Elble { 45357fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 45367fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 45377fc0564eSAndrew Elble 45387fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 45397fc0564eSAndrew Elble 45407fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 45417fc0564eSAndrew Elble /* ignore lock owners */ 45427fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 45437fc0564eSAndrew Elble continue; 454415ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 454515ca08d3STrond Myklebust continue; 454615ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 45477fc0564eSAndrew Elble ret = local; 4548a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 45497fc0564eSAndrew Elble break; 45507fc0564eSAndrew Elble } 45517fc0564eSAndrew Elble } 45527fc0564eSAndrew Elble return ret; 45537fc0564eSAndrew Elble } 45547fc0564eSAndrew Elble 455515ca08d3STrond Myklebust static __be32 455615ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 455715ca08d3STrond Myklebust { 455815ca08d3STrond Myklebust __be32 ret = nfs_ok; 455915ca08d3STrond Myklebust 456015ca08d3STrond Myklebust switch (s->sc_type) { 456115ca08d3STrond Myklebust default: 456215ca08d3STrond Myklebust break; 45634f176417STrond Myklebust case 0: 456415ca08d3STrond Myklebust case NFS4_CLOSED_STID: 456515ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 456615ca08d3STrond Myklebust ret = nfserr_bad_stateid; 456715ca08d3STrond Myklebust break; 456815ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 456915ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 457015ca08d3STrond Myklebust } 457115ca08d3STrond Myklebust return ret; 457215ca08d3STrond Myklebust } 457315ca08d3STrond Myklebust 457415ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 457515ca08d3STrond Myklebust static __be32 457615ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 457715ca08d3STrond Myklebust { 457815ca08d3STrond Myklebust __be32 ret; 457915ca08d3STrond Myklebust 45804f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 458115ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 458215ca08d3STrond Myklebust if (ret != nfs_ok) 458315ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 458415ca08d3STrond Myklebust return ret; 458515ca08d3STrond Myklebust } 458615ca08d3STrond Myklebust 458715ca08d3STrond Myklebust static struct nfs4_ol_stateid * 458815ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 458915ca08d3STrond Myklebust { 459015ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 459115ca08d3STrond Myklebust for (;;) { 459215ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 459315ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 459415ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 459515ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 459615ca08d3STrond Myklebust break; 459715ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 459815ca08d3STrond Myklebust } 459915ca08d3STrond Myklebust return stp; 460015ca08d3STrond Myklebust } 460115ca08d3STrond Myklebust 4602fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 460313d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 4604db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 4605db24b3b4SJeff Layton { 460613d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 46077ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 46081da177e4SLinus Torvalds 4609fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 4610fe0750e5SJ. Bruce Fields if (!oo) 46111da177e4SLinus Torvalds return NULL; 46126b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 4613fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 4614fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 4615d3134b10SJeff Layton oo->oo_flags = 0; 4616db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 4617db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 4618fe0750e5SJ. Bruce Fields oo->oo_time = 0; 461938c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 4620fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 4621d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 4622d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 46237ffb5880STrond Myklebust if (ret == NULL) { 4624fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 46257ffb5880STrond Myklebust ret = oo; 46267ffb5880STrond Myklebust } else 4627d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 4628d50ffdedSKinglong Mee 4629d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 4630c5952338SJeff Layton return ret; 46311da177e4SLinus Torvalds } 46321da177e4SLinus Torvalds 46337fc0564eSAndrew Elble static struct nfs4_ol_stateid * 46348c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 46357fc0564eSAndrew Elble { 46361da177e4SLinus Torvalds 46377fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 46387fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 46398c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 46407fc0564eSAndrew Elble 46418c7245abSOleg Drokin stp = open->op_stp; 46425cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 46435cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 46444f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 46455cc1fb2aSOleg Drokin 464615ca08d3STrond Myklebust retry: 46477fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 46487fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 46497fc0564eSAndrew Elble 46507fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 46517fc0564eSAndrew Elble if (retstp) 46527fc0564eSAndrew Elble goto out_unlock; 46538c7245abSOleg Drokin 46548c7245abSOleg Drokin open->op_stp = NULL; 4655a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 46563abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 46573c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 4658b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 465913cd2184SNeilBrown get_nfs4_file(fp); 466011b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 46611da177e4SLinus Torvalds stp->st_access_bmap = 0; 46621da177e4SLinus Torvalds stp->st_deny_bmap = 0; 46634c4cd222SNeilBrown stp->st_openstp = NULL; 46641c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 46651d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 46667fc0564eSAndrew Elble 46677fc0564eSAndrew Elble out_unlock: 46681d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 46691c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 46705cc1fb2aSOleg Drokin if (retstp) { 467115ca08d3STrond Myklebust /* Handle races with CLOSE */ 467215ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 467315ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 467415ca08d3STrond Myklebust goto retry; 467515ca08d3STrond Myklebust } 46768c7245abSOleg Drokin /* To keep mutex tracking happy */ 46775cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 46788c7245abSOleg Drokin stp = retstp; 46795cc1fb2aSOleg Drokin } 46808c7245abSOleg Drokin return stp; 46811da177e4SLinus Torvalds } 46821da177e4SLinus Torvalds 4683d3134b10SJeff Layton /* 4684d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 4685d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 4686d3134b10SJeff Layton * them before returning however. 4687d3134b10SJeff Layton */ 46881da177e4SLinus Torvalds static void 4689d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 46901da177e4SLinus Torvalds { 4691217526e7SJeff Layton struct nfs4_ol_stateid *last; 4692d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 4693d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 4694d3134b10SJeff Layton nfsd_net_id); 469573758fedSStanislav Kinsbursky 4696fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 46971da177e4SLinus Torvalds 4698b401be22SJeff Layton /* 4699b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 4700b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 4701b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 4702b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 4703b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 4704b401be22SJeff Layton * there should be no danger of the refcount going back up again at 4705b401be22SJeff Layton * this point. 4706b401be22SJeff Layton */ 4707a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 4708b401be22SJeff Layton 4709d3134b10SJeff Layton release_all_access(s); 4710d3134b10SJeff Layton if (s->st_stid.sc_file) { 4711d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 4712d3134b10SJeff Layton s->st_stid.sc_file = NULL; 4713d3134b10SJeff Layton } 4714217526e7SJeff Layton 4715217526e7SJeff Layton spin_lock(&nn->client_lock); 4716217526e7SJeff Layton last = oo->oo_last_closed_stid; 4717d3134b10SJeff Layton oo->oo_last_closed_stid = s; 471873758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 471920b7d86fSArnd Bergmann oo->oo_time = ktime_get_boottime_seconds(); 4720217526e7SJeff Layton spin_unlock(&nn->client_lock); 4721217526e7SJeff Layton if (last) 4722217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 47231da177e4SLinus Torvalds } 47241da177e4SLinus Torvalds 472515424748SChuck Lever static noinline_for_stack struct nfs4_file * 472615424748SChuck Lever nfsd4_file_hash_lookup(const struct svc_fh *fhp) 47271da177e4SLinus Torvalds { 4728d47b295eSChuck Lever struct inode *inode = d_inode(fhp->fh_dentry); 4729d47b295eSChuck Lever struct rhlist_head *tmp, *list; 473015424748SChuck Lever struct nfs4_file *fi; 4731950e0118STrond Myklebust 47325b095e99SJeff Layton rcu_read_lock(); 4733d47b295eSChuck Lever list = rhltable_lookup(&nfs4_file_rhltable, &inode, 4734d47b295eSChuck Lever nfs4_file_rhash_params); 4735d47b295eSChuck Lever rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) { 473615424748SChuck Lever if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { 473715424748SChuck Lever if (refcount_inc_not_zero(&fi->fi_ref)) { 47385b095e99SJeff Layton rcu_read_unlock(); 473915424748SChuck Lever return fi; 474015424748SChuck Lever } 474115424748SChuck Lever } 474215424748SChuck Lever } 474315424748SChuck Lever rcu_read_unlock(); 474415424748SChuck Lever return NULL; 4745950e0118STrond Myklebust } 4746950e0118STrond Myklebust 47479270fc51SChuck Lever /* 47489270fc51SChuck Lever * On hash insertion, identify entries with the same inode but 4749d47b295eSChuck Lever * distinct filehandles. They will all be on the list returned 4750d47b295eSChuck Lever * by rhltable_lookup(). 4751d47b295eSChuck Lever * 4752d47b295eSChuck Lever * inode->i_lock prevents racing insertions from adding an entry 4753d47b295eSChuck Lever * for the same inode/fhp pair twice. 47549270fc51SChuck Lever */ 47559270fc51SChuck Lever static noinline_for_stack struct nfs4_file * 47569270fc51SChuck Lever nfsd4_file_hash_insert(struct nfs4_file *new, const struct svc_fh *fhp) 4757950e0118STrond Myklebust { 4758d47b295eSChuck Lever struct inode *inode = d_inode(fhp->fh_dentry); 4759d47b295eSChuck Lever struct rhlist_head *tmp, *list; 47609270fc51SChuck Lever struct nfs4_file *ret = NULL; 47619270fc51SChuck Lever bool alias_found = false; 47629270fc51SChuck Lever struct nfs4_file *fi; 4763d47b295eSChuck Lever int err; 47645b095e99SJeff Layton 4765d47b295eSChuck Lever rcu_read_lock(); 4766d47b295eSChuck Lever spin_lock(&inode->i_lock); 4767d47b295eSChuck Lever 4768d47b295eSChuck Lever list = rhltable_lookup(&nfs4_file_rhltable, &inode, 4769d47b295eSChuck Lever nfs4_file_rhash_params); 4770d47b295eSChuck Lever rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) { 47719270fc51SChuck Lever if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { 47729270fc51SChuck Lever if (refcount_inc_not_zero(&fi->fi_ref)) 47739270fc51SChuck Lever ret = fi; 4774d47b295eSChuck Lever } else 47759270fc51SChuck Lever fi->fi_aliased = alias_found = true; 47769270fc51SChuck Lever } 4777d47b295eSChuck Lever if (ret) 4778d47b295eSChuck Lever goto out_unlock; 4779d47b295eSChuck Lever 47809270fc51SChuck Lever nfsd4_file_init(fhp, new); 4781d47b295eSChuck Lever err = rhltable_insert(&nfs4_file_rhltable, &new->fi_rlist, 4782d47b295eSChuck Lever nfs4_file_rhash_params); 4783d47b295eSChuck Lever if (err) 4784d47b295eSChuck Lever goto out_unlock; 4785d47b295eSChuck Lever 47869270fc51SChuck Lever new->fi_aliased = alias_found; 47879270fc51SChuck Lever ret = new; 4788d47b295eSChuck Lever 4789d47b295eSChuck Lever out_unlock: 4790d47b295eSChuck Lever spin_unlock(&inode->i_lock); 4791d47b295eSChuck Lever rcu_read_unlock(); 47929270fc51SChuck Lever return ret; 4793950e0118STrond Myklebust } 4794950e0118STrond Myklebust 47953341678fSChuck Lever static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi) 47963341678fSChuck Lever { 4797d47b295eSChuck Lever rhltable_remove(&nfs4_file_rhltable, &fi->fi_rlist, 4798d47b295eSChuck Lever nfs4_file_rhash_params); 47993341678fSChuck Lever } 48003341678fSChuck Lever 48014f83aa30SJ. Bruce Fields /* 48021da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 48031da177e4SLinus Torvalds * WRITE with all zero or all one stateid 48041da177e4SLinus Torvalds */ 4805b37ad28bSAl Viro static __be32 48061da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 48071da177e4SLinus Torvalds { 48081da177e4SLinus Torvalds struct nfs4_file *fp; 4809baeb4ff0SJeff Layton __be32 ret = nfs_ok; 48101da177e4SLinus Torvalds 481115424748SChuck Lever fp = nfsd4_file_hash_lookup(current_fh); 481213cd2184SNeilBrown if (!fp) 4813baeb4ff0SJeff Layton return ret; 481415424748SChuck Lever 4815baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 48161d31a253STrond Myklebust spin_lock(&fp->fi_lock); 4817baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 4818baeb4ff0SJeff Layton ret = nfserr_locked; 48191d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 482013cd2184SNeilBrown put_nfs4_file(fp); 482113cd2184SNeilBrown return ret; 48221da177e4SLinus Torvalds } 48231da177e4SLinus Torvalds 4824c035362eSChuck Lever static bool nfsd4_deleg_present(const struct inode *inode) 4825c035362eSChuck Lever { 4826c035362eSChuck Lever struct file_lock_context *ctx = smp_load_acquire(&inode->i_flctx); 4827c035362eSChuck Lever 4828c035362eSChuck Lever return ctx && !list_empty_careful(&ctx->flc_lease); 4829c035362eSChuck Lever } 4830c035362eSChuck Lever 4831c035362eSChuck Lever /** 4832c035362eSChuck Lever * nfsd_wait_for_delegreturn - wait for delegations to be returned 4833c035362eSChuck Lever * @rqstp: the RPC transaction being executed 4834c035362eSChuck Lever * @inode: in-core inode of the file being waited for 4835c035362eSChuck Lever * 4836c035362eSChuck Lever * The timeout prevents deadlock if all nfsd threads happen to be 4837c035362eSChuck Lever * tied up waiting for returning delegations. 4838c035362eSChuck Lever * 4839c035362eSChuck Lever * Return values: 4840c035362eSChuck Lever * %true: delegation was returned 4841c035362eSChuck Lever * %false: timed out waiting for delegreturn 4842c035362eSChuck Lever */ 4843c035362eSChuck Lever bool nfsd_wait_for_delegreturn(struct svc_rqst *rqstp, struct inode *inode) 4844c035362eSChuck Lever { 4845c035362eSChuck Lever long __maybe_unused timeo; 4846c035362eSChuck Lever 4847c035362eSChuck Lever timeo = wait_var_event_timeout(inode, !nfsd4_deleg_present(inode), 4848c035362eSChuck Lever NFSD_DELEGRETURN_TIMEOUT); 4849c035362eSChuck Lever trace_nfsd_delegret_wakeup(rqstp, inode, timeo); 4850c035362eSChuck Lever return timeo > 0; 4851c035362eSChuck Lever } 4852c035362eSChuck Lever 48530162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 48541da177e4SLinus Torvalds { 48550162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 485611b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 485711b9164aSTrond Myklebust nfsd_net_id); 4858e8c69d17SJ. Bruce Fields 485911b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 4860f54fe962SJeff Layton 486102e1215fSJeff Layton /* 486202e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 4863f54fe962SJeff Layton * already holding inode->i_lock. 4864f54fe962SJeff Layton * 4865dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 4866dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 4867dff1399fSJeff Layton */ 4868f54fe962SJeff Layton spin_lock(&state_lock); 4869548ec080SJ. Bruce Fields if (delegation_hashed(dp) && dp->dl_time == 0) { 487020b7d86fSArnd Bergmann dp->dl_time = ktime_get_boottime_seconds(); 487102e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 487202e1215fSJeff Layton } 487302e1215fSJeff Layton spin_unlock(&state_lock); 4874dff1399fSJeff Layton } 48751da177e4SLinus Torvalds 48760162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 48770162ac2bSChristoph Hellwig struct rpc_task *task) 48780162ac2bSChristoph Hellwig { 48790162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 48800162ac2bSChristoph Hellwig 48811035d654SChuck Lever trace_nfsd_cb_recall_done(&dp->dl_stid.sc_stateid, task); 48821035d654SChuck Lever 488312ed22f3SJ. Bruce Fields if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID || 488412ed22f3SJ. Bruce Fields dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4885a457974fSAndrew Elble return 1; 4886a457974fSAndrew Elble 48870162ac2bSChristoph Hellwig switch (task->tk_status) { 48880162ac2bSChristoph Hellwig case 0: 48890162ac2bSChristoph Hellwig return 1; 48901c73b9d2SScott Mayhew case -NFS4ERR_DELAY: 48911c73b9d2SScott Mayhew rpc_delay(task, 2 * HZ); 48921c73b9d2SScott Mayhew return 0; 48930162ac2bSChristoph Hellwig case -EBADHANDLE: 48940162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 48950162ac2bSChristoph Hellwig /* 48960162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 48970162ac2bSChristoph Hellwig * granting delegation. 48980162ac2bSChristoph Hellwig */ 48990162ac2bSChristoph Hellwig if (dp->dl_retries--) { 49000162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 49010162ac2bSChristoph Hellwig return 0; 49020162ac2bSChristoph Hellwig } 4903df561f66SGustavo A. R. Silva fallthrough; 49040162ac2bSChristoph Hellwig default: 49051c73b9d2SScott Mayhew return 1; 49060162ac2bSChristoph Hellwig } 49070162ac2bSChristoph Hellwig } 49080162ac2bSChristoph Hellwig 49090162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 49100162ac2bSChristoph Hellwig { 49110162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 49120162ac2bSChristoph Hellwig 49130162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 49140162ac2bSChristoph Hellwig } 49150162ac2bSChristoph Hellwig 4916c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 49170162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 49180162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 49190162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 49200162ac2bSChristoph Hellwig }; 49210162ac2bSChristoph Hellwig 492202e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 492302e1215fSJeff Layton { 492402e1215fSJeff Layton /* 492502e1215fSJeff Layton * We're assuming the state code never drops its reference 492602e1215fSJeff Layton * without first removing the lease. Since we're in this lease 49274a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 492825fbe1fcSJeff Layton * flc_lock) we know the server hasn't removed the lease yet, and 49294a269efbSJ. Bruce Fields * we know it's safe to take a reference. 493002e1215fSJeff Layton */ 4931a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 4932b95239caSJeff Layton WARN_ON_ONCE(!nfsd4_run_cb(&dp->dl_recall)); 49336b57d9c8SJ. Bruce Fields } 49346b57d9c8SJ. Bruce Fields 493525fbe1fcSJeff Layton /* Called from break_lease() with flc_lock held. */ 49364d01b7f5SJeff Layton static bool 49374d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 49386b57d9c8SJ. Bruce Fields { 4939653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 4940653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 494166af2579SDai Ngo struct nfs4_client *clp = dp->dl_stid.sc_client; 494266af2579SDai Ngo struct nfsd_net *nn; 49436b57d9c8SJ. Bruce Fields 494417d76ddfSChuck Lever trace_nfsd_cb_recall(&dp->dl_stid); 4945dd5e3fbcSChuck Lever 494666af2579SDai Ngo dp->dl_recalled = true; 494766af2579SDai Ngo atomic_inc(&clp->cl_delegs_in_recall); 494866af2579SDai Ngo if (try_to_expire_client(clp)) { 494966af2579SDai Ngo nn = net_generic(clp->net, nfsd_net_id); 495066af2579SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 495166af2579SDai Ngo } 495266af2579SDai Ngo 49530272e1fdSJ. Bruce Fields /* 49540272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 4955acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 49566b57d9c8SJ. Bruce Fields * in time: 49570272e1fdSJ. Bruce Fields */ 49580272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 49591da177e4SLinus Torvalds 496002e1215fSJeff Layton spin_lock(&fp->fi_lock); 4961417c6629SJeff Layton fp->fi_had_conflict = true; 49625d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 496302e1215fSJeff Layton spin_unlock(&fp->fi_lock); 4964b95239caSJeff Layton return false; 49651da177e4SLinus Torvalds } 49661da177e4SLinus Torvalds 496750719bf3SChuck Lever /** 496850719bf3SChuck Lever * nfsd_breaker_owns_lease - Check if lease conflict was resolved 496950719bf3SChuck Lever * @fl: Lock state to check 497050719bf3SChuck Lever * 497150719bf3SChuck Lever * Return values: 497250719bf3SChuck Lever * %true: Lease conflict was resolved 497350719bf3SChuck Lever * %false: Lease conflict was not resolved. 497450719bf3SChuck Lever */ 497528df3d15SJ. Bruce Fields static bool nfsd_breaker_owns_lease(struct file_lock *fl) 497628df3d15SJ. Bruce Fields { 497728df3d15SJ. Bruce Fields struct nfs4_delegation *dl = fl->fl_owner; 497828df3d15SJ. Bruce Fields struct svc_rqst *rqst; 497928df3d15SJ. Bruce Fields struct nfs4_client *clp; 498028df3d15SJ. Bruce Fields 498128df3d15SJ. Bruce Fields if (!i_am_nfsd()) 498250719bf3SChuck Lever return false; 498328df3d15SJ. Bruce Fields rqst = kthread_data(current); 498413956160SJ. Bruce Fields /* Note rq_prog == NFS_ACL_PROGRAM is also possible: */ 498513956160SJ. Bruce Fields if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4) 498650719bf3SChuck Lever return false; 498728df3d15SJ. Bruce Fields clp = *(rqst->rq_lease_breaker); 498828df3d15SJ. Bruce Fields return dl->dl_stid.sc_client == clp; 498928df3d15SJ. Bruce Fields } 499028df3d15SJ. Bruce Fields 4991c45198edSJeff Layton static int 49927448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 49937448cc37SJeff Layton struct list_head *dispose) 49941da177e4SLinus Torvalds { 499566af2579SDai Ngo struct nfs4_delegation *dp = (struct nfs4_delegation *)onlist->fl_owner; 499666af2579SDai Ngo struct nfs4_client *clp = dp->dl_stid.sc_client; 499766af2579SDai Ngo 499866af2579SDai Ngo if (arg & F_UNLCK) { 499966af2579SDai Ngo if (dp->dl_recalled) 500066af2579SDai Ngo atomic_dec(&clp->cl_delegs_in_recall); 5001c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 500266af2579SDai Ngo } else 50031da177e4SLinus Torvalds return -EAGAIN; 50041da177e4SLinus Torvalds } 50051da177e4SLinus Torvalds 50067b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 500728df3d15SJ. Bruce Fields .lm_breaker_owns_lease = nfsd_breaker_owns_lease, 50088fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 50098fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 50101da177e4SLinus Torvalds }; 50111da177e4SLinus Torvalds 50127a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 50137a8711c9SJ. Bruce Fields { 50147a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 50157a8711c9SJ. Bruce Fields return nfs_ok; 50167a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 50177a8711c9SJ. Bruce Fields return nfserr_replay_me; 50187a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 50197a8711c9SJ. Bruce Fields return nfs_ok; 50207a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 50217a8711c9SJ. Bruce Fields } 50221da177e4SLinus Torvalds 50237950b531SJ. Bruce Fields static struct nfs4_client *lookup_clientid(clientid_t *clid, bool sessions, 50247950b531SJ. Bruce Fields struct nfsd_net *nn) 50257950b531SJ. Bruce Fields { 50267950b531SJ. Bruce Fields struct nfs4_client *found; 50277950b531SJ. Bruce Fields 50287950b531SJ. Bruce Fields spin_lock(&nn->client_lock); 50297950b531SJ. Bruce Fields found = find_confirmed_client(clid, sessions, nn); 50307950b531SJ. Bruce Fields if (found) 50317950b531SJ. Bruce Fields atomic_inc(&found->cl_rpc_users); 50327950b531SJ. Bruce Fields spin_unlock(&nn->client_lock); 50337950b531SJ. Bruce Fields return found; 50347950b531SJ. Bruce Fields } 50357950b531SJ. Bruce Fields 5036460d2709SJ. Bruce Fields static __be32 set_client(clientid_t *clid, 50374b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 5038f71475baSJ. Bruce Fields struct nfsd_net *nn) 50394b24ca7dSJeff Layton { 50404b24ca7dSJeff Layton if (cstate->clp) { 50417950b531SJ. Bruce Fields if (!same_clid(&cstate->clp->cl_clientid, clid)) 50424b24ca7dSJeff Layton return nfserr_stale_clientid; 50434b24ca7dSJeff Layton return nfs_ok; 50444b24ca7dSJeff Layton } 50454b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 50464b24ca7dSJeff Layton return nfserr_stale_clientid; 50474b24ca7dSJeff Layton /* 5048f71475baSJ. Bruce Fields * We're in the 4.0 case (otherwise the SEQUENCE op would have 5049f71475baSJ. Bruce Fields * set cstate->clp), so session = false: 50504b24ca7dSJeff Layton */ 5051f71475baSJ. Bruce Fields cstate->clp = lookup_clientid(clid, false, nn); 50527950b531SJ. Bruce Fields if (!cstate->clp) 50534b24ca7dSJeff Layton return nfserr_expired; 50544b24ca7dSJeff Layton return nfs_ok; 50554b24ca7dSJeff Layton } 50564b24ca7dSJeff Layton 5057b37ad28bSAl Viro __be32 50586668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 50593320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 50601da177e4SLinus Torvalds { 50611da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 50621da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 50631da177e4SLinus Torvalds unsigned int strhashval; 5064fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 50654cdc951bSJ. Bruce Fields __be32 status; 50661da177e4SLinus Torvalds 506732513b40SJ. Bruce Fields /* 506832513b40SJ. Bruce Fields * In case we need it later, after we've already created the 506932513b40SJ. Bruce Fields * file and don't want to risk a further failure: 507032513b40SJ. Bruce Fields */ 507132513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 507232513b40SJ. Bruce Fields if (open->op_file == NULL) 507332513b40SJ. Bruce Fields return nfserr_jukebox; 50741da177e4SLinus Torvalds 5075f71475baSJ. Bruce Fields status = set_client(clientid, cstate, nn); 507613d6f66bSTrond Myklebust if (status) 507713d6f66bSTrond Myklebust return status; 507813d6f66bSTrond Myklebust clp = cstate->clp; 50792d91e895STrond Myklebust 5080d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 5081d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 50822d91e895STrond Myklebust open->op_openowner = oo; 50832d91e895STrond Myklebust if (!oo) { 5084bcf130f9SJ. Bruce Fields goto new_owner; 50850f442aa2SJ. Bruce Fields } 5086dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 50870f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 5088fe0750e5SJ. Bruce Fields release_openowner(oo); 5089fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 5090bcf130f9SJ. Bruce Fields goto new_owner; 50910f442aa2SJ. Bruce Fields } 50924cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 50934cdc951bSJ. Bruce Fields if (status) 50944cdc951bSJ. Bruce Fields return status; 50954cdc951bSJ. Bruce Fields goto alloc_stateid; 5096bcf130f9SJ. Bruce Fields new_owner: 509713d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 5098fe0750e5SJ. Bruce Fields if (oo == NULL) 50993e772463SJ. Bruce Fields return nfserr_jukebox; 5100fe0750e5SJ. Bruce Fields open->op_openowner = oo; 51014cdc951bSJ. Bruce Fields alloc_stateid: 5102b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 51034cdc951bSJ. Bruce Fields if (!open->op_stp) 51044cdc951bSJ. Bruce Fields return nfserr_jukebox; 51058287f009SSachin Bhamare 51068287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 51078287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 51088287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 51098287f009SSachin Bhamare if (!open->op_odstate) 51108287f009SSachin Bhamare return nfserr_jukebox; 51118287f009SSachin Bhamare } 51128287f009SSachin Bhamare 51130f442aa2SJ. Bruce Fields return nfs_ok; 51141da177e4SLinus Torvalds } 51151da177e4SLinus Torvalds 5116b37ad28bSAl Viro static inline __be32 51174a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 51184a6e43e6SNeilBrown { 51194a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 51204a6e43e6SNeilBrown return nfserr_openmode; 51214a6e43e6SNeilBrown else 51224a6e43e6SNeilBrown return nfs_ok; 51234a6e43e6SNeilBrown } 51244a6e43e6SNeilBrown 5125c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 512624a0111eSJ. Bruce Fields { 512724a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 512824a0111eSJ. Bruce Fields } 512924a0111eSJ. Bruce Fields 513038c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 5131f459e453SJ. Bruce Fields { 5132f459e453SJ. Bruce Fields struct nfs4_stid *ret; 5133f459e453SJ. Bruce Fields 513495da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 513595da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 5136f459e453SJ. Bruce Fields if (!ret) 5137f459e453SJ. Bruce Fields return NULL; 5138f459e453SJ. Bruce Fields return delegstateid(ret); 5139f459e453SJ. Bruce Fields } 5140f459e453SJ. Bruce Fields 51418b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 51428b289b2cSJ. Bruce Fields { 51438b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 51448b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 51458b289b2cSJ. Bruce Fields } 51468b289b2cSJ. Bruce Fields 5147b37ad28bSAl Viro static __be32 514841d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 5149567d9829SNeilBrown struct nfs4_delegation **dp) 5150567d9829SNeilBrown { 5151567d9829SNeilBrown int flags; 5152b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 5153dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 5154567d9829SNeilBrown 5155dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 5156dcd94cc2STrond Myklebust if (deleg == NULL) 5157c44c5eebSNeilBrown goto out; 515895da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 515995da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 516095da1b3aSAndrew Elble if (cl->cl_minorversion) 516195da1b3aSAndrew Elble status = nfserr_deleg_revoked; 516295da1b3aSAndrew Elble goto out; 516395da1b3aSAndrew Elble } 516424a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 5165dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 5166dcd94cc2STrond Myklebust if (status) { 5167dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 5168dcd94cc2STrond Myklebust goto out; 5169dcd94cc2STrond Myklebust } 5170dcd94cc2STrond Myklebust *dp = deleg; 5171c44c5eebSNeilBrown out: 51728b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 5173c44c5eebSNeilBrown return nfs_ok; 5174c44c5eebSNeilBrown if (status) 5175c44c5eebSNeilBrown return status; 5176dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 5177c44c5eebSNeilBrown return nfs_ok; 5178567d9829SNeilBrown } 5179567d9829SNeilBrown 518021fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 518121fb4016SJ. Bruce Fields { 518221fb4016SJ. Bruce Fields int flags = 0; 518321fb4016SJ. Bruce Fields 518421fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 518521fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 518621fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 518721fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 518821fb4016SJ. Bruce Fields return flags; 518921fb4016SJ. Bruce Fields } 519021fb4016SJ. Bruce Fields 5191b37ad28bSAl Viro static inline __be32 51921da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 51931da177e4SLinus Torvalds struct nfsd4_open *open) 51941da177e4SLinus Torvalds { 51951da177e4SLinus Torvalds struct iattr iattr = { 51961da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 51971da177e4SLinus Torvalds .ia_size = 0, 51981da177e4SLinus Torvalds }; 51997fe2a71dSNeilBrown struct nfsd_attrs attrs = { 52007fe2a71dSNeilBrown .na_iattr = &iattr, 52017fe2a71dSNeilBrown }; 52021da177e4SLinus Torvalds if (!open->op_truncate) 52031da177e4SLinus Torvalds return 0; 52041da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 52059246585aSAl Viro return nfserr_inval; 52067fe2a71dSNeilBrown return nfsd_setattr(rqstp, fh, &attrs, 0, (time64_t)0); 52071da177e4SLinus Torvalds } 52081da177e4SLinus Torvalds 52097e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 52106eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 52113d694271SDai Ngo struct nfsd4_open *open, bool new_stp) 52127e6a72e5SChristoph Hellwig { 5213fd4f83fdSJeff Layton struct nfsd_file *nf = NULL; 52147e6a72e5SChristoph Hellwig __be32 status; 52157e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 52167e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 5217baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 52187e6a72e5SChristoph Hellwig 5219de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 5220baeb4ff0SJeff Layton 5221baeb4ff0SJeff Layton /* 5222baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 5223baeb4ff0SJeff Layton * current access? 5224baeb4ff0SJeff Layton */ 5225baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 5226baeb4ff0SJeff Layton if (status != nfs_ok) { 52273d694271SDai Ngo if (status != nfserr_share_denied) { 52283d694271SDai Ngo spin_unlock(&fp->fi_lock); 52293d694271SDai Ngo goto out; 52303d694271SDai Ngo } 52313d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, 52323d694271SDai Ngo stp, open->op_share_deny, false)) 52333d694271SDai Ngo status = nfserr_jukebox; 5234baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 5235baeb4ff0SJeff Layton goto out; 5236baeb4ff0SJeff Layton } 5237baeb4ff0SJeff Layton 5238baeb4ff0SJeff Layton /* set access to the file */ 5239baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 5240baeb4ff0SJeff Layton if (status != nfs_ok) { 52413d694271SDai Ngo if (status != nfserr_share_denied) { 52423d694271SDai Ngo spin_unlock(&fp->fi_lock); 52433d694271SDai Ngo goto out; 52443d694271SDai Ngo } 52453d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, 52463d694271SDai Ngo stp, open->op_share_access, true)) 52473d694271SDai Ngo status = nfserr_jukebox; 5248baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 5249baeb4ff0SJeff Layton goto out; 5250baeb4ff0SJeff Layton } 5251baeb4ff0SJeff Layton 5252baeb4ff0SJeff Layton /* Set access bits in stateid */ 5253baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 5254baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 5255baeb4ff0SJeff Layton 5256baeb4ff0SJeff Layton /* Set new deny mask */ 5257baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 5258baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 5259baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 5260baeb4ff0SJeff Layton 52617e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 5262de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 5263fb70bf12SChuck Lever 5264fb70bf12SChuck Lever if (!open->op_filp) { 5265fd4f83fdSJeff Layton status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); 5266fb70bf12SChuck Lever if (status != nfs_ok) 5267baeb4ff0SJeff Layton goto out_put_access; 5268fb70bf12SChuck Lever } else { 5269fb70bf12SChuck Lever status = nfsd_file_create(rqstp, cur_fh, access, &nf); 5270fb70bf12SChuck Lever if (status != nfs_ok) 5271fb70bf12SChuck Lever goto out_put_access; 5272fb70bf12SChuck Lever nf->nf_file = open->op_filp; 5273fb70bf12SChuck Lever open->op_filp = NULL; 5274be023006SChuck Lever trace_nfsd_file_create(rqstp, access, nf); 5275fb70bf12SChuck Lever } 5276fb70bf12SChuck Lever 5277de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 5278de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 5279fd4f83fdSJeff Layton fp->fi_fds[oflag] = nf; 5280fd4f83fdSJeff Layton nf = NULL; 5281de18643dSTrond Myklebust } 52827e6a72e5SChristoph Hellwig } 5283de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 5284fd4f83fdSJeff Layton if (nf) 5285fd4f83fdSJeff Layton nfsd_file_put(nf); 52867e6a72e5SChristoph Hellwig 5287217fd6f6SJ. Bruce Fields status = nfserrno(nfsd_open_break_lease(cur_fh->fh_dentry->d_inode, 5288217fd6f6SJ. Bruce Fields access)); 5289217fd6f6SJ. Bruce Fields if (status) 5290217fd6f6SJ. Bruce Fields goto out_put_access; 5291217fd6f6SJ. Bruce Fields 52927e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 52937e6a72e5SChristoph Hellwig if (status) 52947e6a72e5SChristoph Hellwig goto out_put_access; 52957e6a72e5SChristoph Hellwig out: 52967e6a72e5SChristoph Hellwig return status; 5297baeb4ff0SJeff Layton out_put_access: 5298baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 5299baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 5300baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 5301baeb4ff0SJeff Layton goto out; 53027e6a72e5SChristoph Hellwig } 53037e6a72e5SChristoph Hellwig 5304b37ad28bSAl Viro static __be32 53053d694271SDai Ngo nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, 53063d694271SDai Ngo struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 53073d694271SDai Ngo struct nfsd4_open *open) 53081da177e4SLinus Torvalds { 5309b37ad28bSAl Viro __be32 status; 53106ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 53111da177e4SLinus Torvalds 53126eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 53133d694271SDai Ngo return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false); 53147e6a72e5SChristoph Hellwig 5315baeb4ff0SJeff Layton /* test and set deny mode */ 5316baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 5317baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 5318baeb4ff0SJeff Layton if (status == nfs_ok) { 53193d694271SDai Ngo if (status != nfserr_share_denied) { 5320baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 5321baeb4ff0SJeff Layton fp->fi_share_deny |= 5322baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 53233d694271SDai Ngo } else { 53243d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, false, 53253d694271SDai Ngo stp, open->op_share_deny, false)) 53263d694271SDai Ngo status = nfserr_jukebox; 53273d694271SDai Ngo } 53281da177e4SLinus Torvalds } 5329baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 53301da177e4SLinus Torvalds 5331baeb4ff0SJeff Layton if (status != nfs_ok) 5332baeb4ff0SJeff Layton return status; 5333baeb4ff0SJeff Layton 5334baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 5335baeb4ff0SJeff Layton if (status != nfs_ok) 5336baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 5337baeb4ff0SJeff Layton return status; 5338baeb4ff0SJeff Layton } 53391da177e4SLinus Torvalds 534014a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 534114a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 534214a24e99SJ. Bruce Fields { 534314a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 534414a24e99SJ. Bruce Fields return true; 534514a24e99SJ. Bruce Fields /* 534614a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 534714a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 534814a24e99SJ. Bruce Fields * until we hear otherwise: 534914a24e99SJ. Bruce Fields */ 535014a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 535114a24e99SJ. Bruce Fields } 535214a24e99SJ. Bruce Fields 5353653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 5354653e514eSJ. Bruce Fields int flag) 535522d38c4cSJ. Bruce Fields { 535622d38c4cSJ. Bruce Fields struct file_lock *fl; 535722d38c4cSJ. Bruce Fields 535822d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 535922d38c4cSJ. Bruce Fields if (!fl) 536022d38c4cSJ. Bruce Fields return NULL; 536122d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 5362617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 536322d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 536422d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 5365653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 536622d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 5367eb82dd39SJeff Layton fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; 536822d38c4cSJ. Bruce Fields return fl; 536922d38c4cSJ. Bruce Fields } 537022d38c4cSJ. Bruce Fields 5371aba2072fSJ. Bruce Fields static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, 5372aba2072fSJ. Bruce Fields struct nfs4_file *fp) 5373aba2072fSJ. Bruce Fields { 5374aba2072fSJ. Bruce Fields struct nfs4_ol_stateid *st; 5375aba2072fSJ. Bruce Fields struct file *f = fp->fi_deleg_file->nf_file; 5376aba2072fSJ. Bruce Fields struct inode *ino = locks_inode(f); 5377aba2072fSJ. Bruce Fields int writes; 5378aba2072fSJ. Bruce Fields 5379aba2072fSJ. Bruce Fields writes = atomic_read(&ino->i_writecount); 5380aba2072fSJ. Bruce Fields if (!writes) 5381aba2072fSJ. Bruce Fields return 0; 5382aba2072fSJ. Bruce Fields /* 5383aba2072fSJ. Bruce Fields * There could be multiple filehandles (hence multiple 5384aba2072fSJ. Bruce Fields * nfs4_files) referencing this file, but that's not too 5385aba2072fSJ. Bruce Fields * common; let's just give up in that case rather than 5386aba2072fSJ. Bruce Fields * trying to go look up all the clients using that other 5387aba2072fSJ. Bruce Fields * nfs4_file as well: 5388aba2072fSJ. Bruce Fields */ 5389aba2072fSJ. Bruce Fields if (fp->fi_aliased) 5390aba2072fSJ. Bruce Fields return -EAGAIN; 5391aba2072fSJ. Bruce Fields /* 5392aba2072fSJ. Bruce Fields * If there's a close in progress, make sure that we see it 5393aba2072fSJ. Bruce Fields * clear any fi_fds[] entries before we see it decrement 5394aba2072fSJ. Bruce Fields * i_writecount: 5395aba2072fSJ. Bruce Fields */ 5396aba2072fSJ. Bruce Fields smp_mb__after_atomic(); 5397aba2072fSJ. Bruce Fields 5398aba2072fSJ. Bruce Fields if (fp->fi_fds[O_WRONLY]) 5399aba2072fSJ. Bruce Fields writes--; 5400aba2072fSJ. Bruce Fields if (fp->fi_fds[O_RDWR]) 5401aba2072fSJ. Bruce Fields writes--; 5402aba2072fSJ. Bruce Fields if (writes > 0) 5403aba2072fSJ. Bruce Fields return -EAGAIN; /* There may be non-NFSv4 writers */ 5404aba2072fSJ. Bruce Fields /* 5405aba2072fSJ. Bruce Fields * It's possible there are non-NFSv4 write opens in progress, 5406aba2072fSJ. Bruce Fields * but if they haven't incremented i_writecount yet then they 5407aba2072fSJ. Bruce Fields * also haven't called break lease yet; so, they'll break this 5408aba2072fSJ. Bruce Fields * lease soon enough. So, all that's left to check for is NFSv4 5409aba2072fSJ. Bruce Fields * opens: 5410aba2072fSJ. Bruce Fields */ 5411aba2072fSJ. Bruce Fields spin_lock(&fp->fi_lock); 5412aba2072fSJ. Bruce Fields list_for_each_entry(st, &fp->fi_stateids, st_perfile) { 5413aba2072fSJ. Bruce Fields if (st->st_openstp == NULL /* it's an open */ && 5414aba2072fSJ. Bruce Fields access_permit_write(st) && 5415aba2072fSJ. Bruce Fields st->st_stid.sc_client != clp) { 5416aba2072fSJ. Bruce Fields spin_unlock(&fp->fi_lock); 5417aba2072fSJ. Bruce Fields return -EAGAIN; 5418aba2072fSJ. Bruce Fields } 5419aba2072fSJ. Bruce Fields } 5420aba2072fSJ. Bruce Fields spin_unlock(&fp->fi_lock); 5421aba2072fSJ. Bruce Fields /* 5422aba2072fSJ. Bruce Fields * There's a small chance that we could be racing with another 5423aba2072fSJ. Bruce Fields * NFSv4 open. However, any open that hasn't added itself to 5424aba2072fSJ. Bruce Fields * the fi_stateids list also hasn't called break_lease yet; so, 5425aba2072fSJ. Bruce Fields * they'll break this lease soon enough. 5426aba2072fSJ. Bruce Fields */ 5427aba2072fSJ. Bruce Fields return 0; 5428aba2072fSJ. Bruce Fields } 5429aba2072fSJ. Bruce Fields 5430876c553cSJeff Layton /* 5431876c553cSJeff Layton * It's possible that between opening the dentry and setting the delegation, 5432876c553cSJeff Layton * that it has been renamed or unlinked. Redo the lookup to verify that this 5433876c553cSJeff Layton * hasn't happened. 5434876c553cSJeff Layton */ 5435876c553cSJeff Layton static int 5436876c553cSJeff Layton nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp, 5437876c553cSJeff Layton struct svc_fh *parent) 5438876c553cSJeff Layton { 5439876c553cSJeff Layton struct svc_export *exp; 5440876c553cSJeff Layton struct dentry *child; 5441876c553cSJeff Layton __be32 err; 5442876c553cSJeff Layton 5443876c553cSJeff Layton err = nfsd_lookup_dentry(open->op_rqstp, parent, 5444876c553cSJeff Layton open->op_fname, open->op_fnamelen, 5445876c553cSJeff Layton &exp, &child); 5446876c553cSJeff Layton 5447876c553cSJeff Layton if (err) 5448876c553cSJeff Layton return -EAGAIN; 5449876c553cSJeff Layton 545050256e47SJeff Layton exp_put(exp); 5451876c553cSJeff Layton dput(child); 5452876c553cSJeff Layton if (child != file_dentry(fp->fi_deleg_file->nf_file)) 5453876c553cSJeff Layton return -EAGAIN; 5454876c553cSJeff Layton 5455876c553cSJeff Layton return 0; 5456876c553cSJeff Layton } 5457876c553cSJeff Layton 54580b26693cSJeff Layton static struct nfs4_delegation * 5459876c553cSJeff Layton nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, 5460876c553cSJeff Layton struct svc_fh *parent) 5461acfdf5c3SJ. Bruce Fields { 546268b18f52SJ. Bruce Fields int status = 0; 5463876c553cSJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 5464876c553cSJeff Layton struct nfs4_file *fp = stp->st_stid.sc_file; 5465876c553cSJeff Layton struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate; 54660b26693cSJeff Layton struct nfs4_delegation *dp; 5467eb82dd39SJeff Layton struct nfsd_file *nf; 5468353601e7SJ. Bruce Fields struct file_lock *fl; 5469417c6629SJeff Layton 5470353601e7SJ. Bruce Fields /* 5471353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 5472353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 5473353601e7SJ. Bruce Fields * the end: 5474353601e7SJ. Bruce Fields */ 5475bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 54760b26693cSJeff Layton return ERR_PTR(-EAGAIN); 54770b26693cSJeff Layton 5478eb82dd39SJeff Layton nf = find_readable_file(fp); 5479eb82dd39SJeff Layton if (!nf) { 5480aba2072fSJ. Bruce Fields /* 5481aba2072fSJ. Bruce Fields * We probably could attempt another open and get a read 5482aba2072fSJ. Bruce Fields * delegation, but for now, don't bother until the 5483aba2072fSJ. Bruce Fields * client actually sends us one. 5484aba2072fSJ. Bruce Fields */ 5485aba2072fSJ. Bruce Fields return ERR_PTR(-EAGAIN); 5486353601e7SJ. Bruce Fields } 548734ed9872SAndrew Elble spin_lock(&state_lock); 548834ed9872SAndrew Elble spin_lock(&fp->fi_lock); 548968b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 549068b18f52SJ. Bruce Fields status = -EAGAIN; 5491353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 5492eb82dd39SJeff Layton fp->fi_deleg_file = nf; 5493353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 5494353601e7SJ. Bruce Fields * cleared */ 5495353601e7SJ. Bruce Fields fp->fi_delegees = 1; 5496eb82dd39SJeff Layton nf = NULL; 5497353601e7SJ. Bruce Fields } else 5498353601e7SJ. Bruce Fields fp->fi_delegees++; 5499353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 5500353601e7SJ. Bruce Fields spin_unlock(&state_lock); 5501eb82dd39SJeff Layton if (nf) 5502eb82dd39SJeff Layton nfsd_file_put(nf); 5503353601e7SJ. Bruce Fields if (status) 5504353601e7SJ. Bruce Fields return ERR_PTR(status); 5505353601e7SJ. Bruce Fields 5506353601e7SJ. Bruce Fields status = -ENOMEM; 5507bbf936edSJeff Layton dp = alloc_init_deleg(clp, fp, odstate); 5508353601e7SJ. Bruce Fields if (!dp) 5509353601e7SJ. Bruce Fields goto out_delegees; 5510353601e7SJ. Bruce Fields 5511353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 5512353601e7SJ. Bruce Fields if (!fl) 5513bd8d7250SAndrew Elble goto out_clnt_odstate; 5514353601e7SJ. Bruce Fields 5515eb82dd39SJeff Layton status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); 5516353601e7SJ. Bruce Fields if (fl) 5517353601e7SJ. Bruce Fields locks_free_lock(fl); 5518353601e7SJ. Bruce Fields if (status) 5519353601e7SJ. Bruce Fields goto out_clnt_odstate; 5520876c553cSJeff Layton 5521876c553cSJeff Layton if (parent) { 5522876c553cSJeff Layton status = nfsd4_verify_deleg_dentry(open, fp, parent); 5523876c553cSJeff Layton if (status) 5524876c553cSJeff Layton goto out_unlock; 5525876c553cSJeff Layton } 5526876c553cSJeff Layton 5527aba2072fSJ. Bruce Fields status = nfsd4_check_conflicting_opens(clp, fp); 5528aba2072fSJ. Bruce Fields if (status) 5529aba2072fSJ. Bruce Fields goto out_unlock; 5530353601e7SJ. Bruce Fields 5531353601e7SJ. Bruce Fields spin_lock(&state_lock); 5532353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 5533353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 5534353601e7SJ. Bruce Fields status = -EAGAIN; 5535353601e7SJ. Bruce Fields else 5536353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 553734ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 553834ed9872SAndrew Elble spin_unlock(&state_lock); 553934ed9872SAndrew Elble 554034ed9872SAndrew Elble if (status) 5541692ad280SAndrew Elble goto out_unlock; 5542692ad280SAndrew Elble 55430b26693cSJeff Layton return dp; 5544692ad280SAndrew Elble out_unlock: 5545eb82dd39SJeff Layton vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); 5546353601e7SJ. Bruce Fields out_clnt_odstate: 5547353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 5548353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 5549353601e7SJ. Bruce Fields out_delegees: 5550353601e7SJ. Bruce Fields put_deleg_file(fp); 5551353601e7SJ. Bruce Fields return ERR_PTR(status); 5552edab9782SJ. Bruce Fields } 5553edab9782SJ. Bruce Fields 55544aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 55554aa8913cSBenny Halevy { 55564aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 55574aa8913cSBenny Halevy if (status == -EAGAIN) 55584aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 55594aa8913cSBenny Halevy else { 55604aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 55614aa8913cSBenny Halevy switch (open->op_deleg_want) { 55624aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 55634aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 55644aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 55654aa8913cSBenny Halevy break; 55664aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 55674aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 55684aa8913cSBenny Halevy break; 55694aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 5570063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 55714aa8913cSBenny Halevy } 55724aa8913cSBenny Halevy } 55734aa8913cSBenny Halevy } 55744aa8913cSBenny Halevy 55751da177e4SLinus Torvalds /* 55761da177e4SLinus Torvalds * Attempt to hand out a delegation. 557799c41515SJ. Bruce Fields * 557899c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 557999c41515SJ. Bruce Fields * proper support for them. 55801da177e4SLinus Torvalds */ 55811da177e4SLinus Torvalds static void 5582876c553cSJeff Layton nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, 5583876c553cSJeff Layton struct svc_fh *currentfh) 55841da177e4SLinus Torvalds { 55851da177e4SLinus Torvalds struct nfs4_delegation *dp; 55864cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 55874cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 5588876c553cSJeff Layton struct svc_fh *parent = NULL; 558914a24e99SJ. Bruce Fields int cb_up; 559099c41515SJ. Bruce Fields int status = 0; 55911da177e4SLinus Torvalds 5592fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 55937b190fecSNeilBrown open->op_recall = 0; 55947b190fecSNeilBrown switch (open->op_claim_type) { 55957b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 55962bf23875SJ. Bruce Fields if (!cb_up) 55977b190fecSNeilBrown open->op_recall = 1; 559899c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 559999c41515SJ. Bruce Fields goto out_no_deleg; 56007b190fecSNeilBrown break; 56017b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 5602876c553cSJeff Layton parent = currentfh; 5603876c553cSJeff Layton fallthrough; 5604ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 560599c41515SJ. Bruce Fields /* 560699c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 5607c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 5608c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 560999c41515SJ. Bruce Fields */ 56104cf59221SJeff Layton if (locks_in_grace(clp->net)) 561199c41515SJ. Bruce Fields goto out_no_deleg; 5612dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 561399c41515SJ. Bruce Fields goto out_no_deleg; 56147b190fecSNeilBrown break; 56157b190fecSNeilBrown default: 561699c41515SJ. Bruce Fields goto out_no_deleg; 56177b190fecSNeilBrown } 5618876c553cSJeff Layton dp = nfs4_set_delegation(open, stp, parent); 56190b26693cSJeff Layton if (IS_ERR(dp)) 5620dd239cc0SJ. Bruce Fields goto out_no_deleg; 56211da177e4SLinus Torvalds 5622d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 56231da177e4SLinus Torvalds 56243caf9175SHou Tao trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); 562599c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 562667cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5627dd239cc0SJ. Bruce Fields return; 5628dd239cc0SJ. Bruce Fields out_no_deleg: 562999c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 56307b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 5631d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 56321da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 5633d08d32e6SJ. Bruce Fields open->op_recall = 1; 5634d08d32e6SJ. Bruce Fields } 5635dd239cc0SJ. Bruce Fields 5636dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 5637dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 5638dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 5639dd239cc0SJ. Bruce Fields return; 56401da177e4SLinus Torvalds } 56411da177e4SLinus Torvalds 5642e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 5643e27f49c3SBenny Halevy struct nfs4_delegation *dp) 5644e27f49c3SBenny Halevy { 5645e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 5646e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5647e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5648e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 5649e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 5650e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5651e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5652e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 5653e27f49c3SBenny Halevy } 5654e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 5655e27f49c3SBenny Halevy * it already has, therefore we don't return 5656e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 5657e27f49c3SBenny Halevy */ 5658e27f49c3SBenny Halevy } 5659e27f49c3SBenny Halevy 56607e2ce0ccSChuck Lever /** 56617e2ce0ccSChuck Lever * nfsd4_process_open2 - finish open processing 56627e2ce0ccSChuck Lever * @rqstp: the RPC transaction being executed 56637e2ce0ccSChuck Lever * @current_fh: NFSv4 COMPOUND's current filehandle 56647e2ce0ccSChuck Lever * @open: OPEN arguments 56657e2ce0ccSChuck Lever * 56667e2ce0ccSChuck Lever * If successful, (1) truncate the file if open->op_truncate was 56677e2ce0ccSChuck Lever * set, (2) set open->op_stateid, (3) set open->op_delegation. 56687e2ce0ccSChuck Lever * 56697e2ce0ccSChuck Lever * Returns %nfs_ok on success; otherwise an nfs4stat value in 56707e2ce0ccSChuck Lever * network byte order is returned. 56717e2ce0ccSChuck Lever */ 5672b37ad28bSAl Viro __be32 56731da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 56741da177e4SLinus Torvalds { 56756668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 567638c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 56771da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 5678dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 5679567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 5680b37ad28bSAl Viro __be32 status; 5681d8a1a000STrond Myklebust bool new_stp = false; 56821da177e4SLinus Torvalds 56831da177e4SLinus Torvalds /* 56841da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 56851da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 56861da177e4SLinus Torvalds * If not found, create the nfs4_file struct 56871da177e4SLinus Torvalds */ 56889270fc51SChuck Lever fp = nfsd4_file_hash_insert(open->op_file, current_fh); 5689d47b295eSChuck Lever if (unlikely(!fp)) 5690d47b295eSChuck Lever return nfserr_jukebox; 5691950e0118STrond Myklebust if (fp != open->op_file) { 569241d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 5693c44c5eebSNeilBrown if (status) 5694c44c5eebSNeilBrown goto out; 569515ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 56961da177e4SLinus Torvalds } else { 5697950e0118STrond Myklebust open->op_file = NULL; 5698c44c5eebSNeilBrown status = nfserr_bad_stateid; 56998b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 5700c44c5eebSNeilBrown goto out; 57011da177e4SLinus Torvalds } 57021da177e4SLinus Torvalds 5703d8a1a000STrond Myklebust if (!stp) { 5704d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 5705d8a1a000STrond Myklebust if (!open->op_stp) 5706d8a1a000STrond Myklebust new_stp = true; 5707d8a1a000STrond Myklebust } 5708d8a1a000STrond Myklebust 57091da177e4SLinus Torvalds /* 57101da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 57111da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 5712d8a1a000STrond Myklebust * 5713d8a1a000STrond Myklebust * stp is already locked. 57141da177e4SLinus Torvalds */ 5715d8a1a000STrond Myklebust if (!new_stp) { 57161da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 5717f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 571835a92fe8SJeff Layton if (status) { 5719feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 57201da177e4SLinus Torvalds goto out; 572135a92fe8SJeff Layton } 57221da177e4SLinus Torvalds } else { 57233d694271SDai Ngo status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true); 57246eb3a1d0SJeff Layton if (status) { 5725d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 57266eb3a1d0SJeff Layton release_open_stateid(stp); 5727d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 57286eb3a1d0SJeff Layton goto out; 57296eb3a1d0SJeff Layton } 57308287f009SSachin Bhamare 57318287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 57328287f009SSachin Bhamare open->op_odstate); 57338287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 57348287f009SSachin Bhamare open->op_odstate = NULL; 57351da177e4SLinus Torvalds } 5736d8a1a000STrond Myklebust 57379767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 5738feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 57391da177e4SLinus Torvalds 5740d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 5741d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 5742d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5743d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 5744d24433cdSBenny Halevy goto nodeleg; 5745d24433cdSBenny Halevy } 5746d24433cdSBenny Halevy } 5747d24433cdSBenny Halevy 57481da177e4SLinus Torvalds /* 57491da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 57501da177e4SLinus Torvalds * OPEN succeeds even if we fail. 57511da177e4SLinus Torvalds */ 5752876c553cSJeff Layton nfs4_open_delegation(open, stp, &resp->cstate.current_fh); 5753d24433cdSBenny Halevy nodeleg: 57541da177e4SLinus Torvalds status = nfs_ok; 57553caf9175SHou Tao trace_nfsd_open(&stp->st_stid.sc_stateid); 57561da177e4SLinus Torvalds out: 5757d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 5758d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 5759e27f49c3SBenny Halevy open->op_deleg_want) 5760e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 5761d24433cdSBenny Halevy 576213cd2184SNeilBrown if (fp) 576313cd2184SNeilBrown put_nfs4_file(fp); 576437515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 576587186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 57661da177e4SLinus Torvalds /* 57671da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 57681da177e4SLinus Torvalds */ 57691da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 577019e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 577119e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 577219e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 57731da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 577419e4c347SJeff Layton 5775dcd94cc2STrond Myklebust if (dp) 5776dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5777d6f2bc5dSTrond Myklebust if (stp) 5778d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 57791da177e4SLinus Torvalds 57801da177e4SLinus Torvalds return status; 57811da177e4SLinus Torvalds } 57821da177e4SLinus Torvalds 578358fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 578442297899SJeff Layton struct nfsd4_open *open) 5785d29b20cdSJ. Bruce Fields { 5786d29b20cdSJ. Bruce Fields if (open->op_openowner) { 5787d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 5788d29b20cdSJ. Bruce Fields 5789d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 5790d3134b10SJeff Layton nfs4_put_stateowner(so); 5791d29b20cdSJ. Bruce Fields } 579232513b40SJ. Bruce Fields if (open->op_file) 57935b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 57944cdc951bSJ. Bruce Fields if (open->op_stp) 57956011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 57968287f009SSachin Bhamare if (open->op_odstate) 57978287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 5798d29b20cdSJ. Bruce Fields } 5799d29b20cdSJ. Bruce Fields 5800b37ad28bSAl Viro __be32 5801b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5802eb69853dSChristoph Hellwig union nfsd4_op_u *u) 58031da177e4SLinus Torvalds { 5804eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 58051da177e4SLinus Torvalds struct nfs4_client *clp; 5806b37ad28bSAl Viro __be32 status; 58077f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 58081da177e4SLinus Torvalds 5809dd5e3fbcSChuck Lever trace_nfsd_clid_renew(clid); 5810f71475baSJ. Bruce Fields status = set_client(clid, cstate, nn); 58119b2ef62bSJ. Bruce Fields if (status) 5812b4587eb2SJ. Bruce Fields return status; 58134b24ca7dSJeff Layton clp = cstate->clp; 5814ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 581577a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 5816b4587eb2SJ. Bruce Fields return nfserr_cb_path_down; 5817b4587eb2SJ. Bruce Fields return nfs_ok; 58181da177e4SLinus Torvalds } 58191da177e4SLinus Torvalds 58207f5ef2e9SJeff Layton void 582112760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 5822a76b4319SNeilBrown { 582333dcc481SJeff Layton /* do nothing if grace period already ended */ 5824a51c84edSStanislav Kinsbursky if (nn->grace_ended) 582533dcc481SJeff Layton return; 582633dcc481SJeff Layton 5827dd5e3fbcSChuck Lever trace_nfsd_grace_complete(nn); 5828a51c84edSStanislav Kinsbursky nn->grace_ended = true; 582970b28235SJ. Bruce Fields /* 583070b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 583170b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 583270b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 583370b28235SJ. Bruce Fields * 583470b28235SJ. Bruce Fields */ 5835919b8049SJeff Layton nfsd4_record_grace_done(nn); 583670b28235SJ. Bruce Fields /* 583770b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 583870b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 583970b28235SJ. Bruce Fields * of luck on the next boot. 584070b28235SJ. Bruce Fields * 584170b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 584270b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 584370b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 584470b28235SJ. Bruce Fields */ 58455e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 584670b28235SJ. Bruce Fields /* 584770b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 584870b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 584970b28235SJ. Bruce Fields * regular locking can resume. 585070b28235SJ. Bruce Fields */ 5851a76b4319SNeilBrown } 5852a76b4319SNeilBrown 585303f318caSJ. Bruce Fields /* 585403f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 585503f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 585603f318caSJ. Bruce Fields */ 585703f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 585803f318caSJ. Bruce Fields { 585920b7d86fSArnd Bergmann time64_t double_grace_period_end = nn->boot_time + 586020b7d86fSArnd Bergmann 2 * nn->nfsd4_lease; 586103f318caSJ. Bruce Fields 5862362063a5SScott Mayhew if (nn->track_reclaim_completes && 5863362063a5SScott Mayhew atomic_read(&nn->nr_reclaim_complete) == 5864362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) 5865362063a5SScott Mayhew return false; 586603f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 586703f318caSJ. Bruce Fields return false; 586803f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 586903f318caSJ. Bruce Fields /* 587003f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 587103f318caSJ. Bruce Fields * still not done, give up: 587203f318caSJ. Bruce Fields */ 587320b7d86fSArnd Bergmann if (ktime_get_boottime_seconds() > double_grace_period_end) 587403f318caSJ. Bruce Fields return false; 587503f318caSJ. Bruce Fields return true; 587603f318caSJ. Bruce Fields } 587703f318caSJ. Bruce Fields 58787f7e7a40SJ. Bruce Fields struct laundry_time { 58797f7e7a40SJ. Bruce Fields time64_t cutoff; 58807f7e7a40SJ. Bruce Fields time64_t new_timeo; 58817f7e7a40SJ. Bruce Fields }; 58827f7e7a40SJ. Bruce Fields 58837f7e7a40SJ. Bruce Fields static bool state_expired(struct laundry_time *lt, time64_t last_refresh) 58847f7e7a40SJ. Bruce Fields { 58857f7e7a40SJ. Bruce Fields time64_t time_remaining; 58867f7e7a40SJ. Bruce Fields 58877f7e7a40SJ. Bruce Fields if (last_refresh < lt->cutoff) 58887f7e7a40SJ. Bruce Fields return true; 58897f7e7a40SJ. Bruce Fields time_remaining = last_refresh - lt->cutoff; 58907f7e7a40SJ. Bruce Fields lt->new_timeo = min(lt->new_timeo, time_remaining); 58917f7e7a40SJ. Bruce Fields return false; 58927f7e7a40SJ. Bruce Fields } 58937f7e7a40SJ. Bruce Fields 5894f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 5895f4e44b39SDai Ngo void nfsd4_ssc_init_umount_work(struct nfsd_net *nn) 5896f4e44b39SDai Ngo { 5897f4e44b39SDai Ngo spin_lock_init(&nn->nfsd_ssc_lock); 5898f4e44b39SDai Ngo INIT_LIST_HEAD(&nn->nfsd_ssc_mount_list); 5899f4e44b39SDai Ngo init_waitqueue_head(&nn->nfsd_ssc_waitq); 5900f4e44b39SDai Ngo } 5901f4e44b39SDai Ngo EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); 5902f4e44b39SDai Ngo 5903f4e44b39SDai Ngo /* 5904f4e44b39SDai Ngo * This is called when nfsd is being shutdown, after all inter_ssc 5905f4e44b39SDai Ngo * cleanup were done, to destroy the ssc delayed unmount list. 5906f4e44b39SDai Ngo */ 5907f4e44b39SDai Ngo static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) 5908f4e44b39SDai Ngo { 5909f47dc2d3SDai Ngo struct nfsd4_ssc_umount_item *ni = NULL; 5910f4e44b39SDai Ngo struct nfsd4_ssc_umount_item *tmp; 5911f4e44b39SDai Ngo 5912f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5913f4e44b39SDai Ngo list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { 5914f4e44b39SDai Ngo list_del(&ni->nsui_list); 5915f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5916f4e44b39SDai Ngo mntput(ni->nsui_vfsmount); 5917f4e44b39SDai Ngo kfree(ni); 5918f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5919f4e44b39SDai Ngo } 5920f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5921f4e44b39SDai Ngo } 5922f4e44b39SDai Ngo 5923f4e44b39SDai Ngo static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) 5924f4e44b39SDai Ngo { 5925f4e44b39SDai Ngo bool do_wakeup = false; 59268e70bf27SColin Ian King struct nfsd4_ssc_umount_item *ni = NULL; 5927f4e44b39SDai Ngo struct nfsd4_ssc_umount_item *tmp; 5928f4e44b39SDai Ngo 5929f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5930f4e44b39SDai Ngo list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { 5931f4e44b39SDai Ngo if (time_after(jiffies, ni->nsui_expire)) { 5932f4e44b39SDai Ngo if (refcount_read(&ni->nsui_refcnt) > 1) 5933f4e44b39SDai Ngo continue; 5934f4e44b39SDai Ngo 5935f4e44b39SDai Ngo /* mark being unmount */ 5936f4e44b39SDai Ngo ni->nsui_busy = true; 5937f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5938f4e44b39SDai Ngo mntput(ni->nsui_vfsmount); 5939f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5940f4e44b39SDai Ngo 5941f4e44b39SDai Ngo /* waiters need to start from begin of list */ 5942f4e44b39SDai Ngo list_del(&ni->nsui_list); 5943f4e44b39SDai Ngo kfree(ni); 5944f4e44b39SDai Ngo 5945f4e44b39SDai Ngo /* wakeup ssc_connect waiters */ 5946f4e44b39SDai Ngo do_wakeup = true; 5947f4e44b39SDai Ngo continue; 5948f4e44b39SDai Ngo } 5949f4e44b39SDai Ngo break; 5950f4e44b39SDai Ngo } 5951f4e44b39SDai Ngo if (do_wakeup) 5952f4e44b39SDai Ngo wake_up_all(&nn->nfsd_ssc_waitq); 5953f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5954f4e44b39SDai Ngo } 5955f4e44b39SDai Ngo #endif 5956f4e44b39SDai Ngo 595727431affSDai Ngo /* Check if any lock belonging to this lockowner has any blockers */ 59583d694271SDai Ngo static bool 595927431affSDai Ngo nfs4_lockowner_has_blockers(struct nfs4_lockowner *lo) 596027431affSDai Ngo { 596127431affSDai Ngo struct file_lock_context *ctx; 596227431affSDai Ngo struct nfs4_ol_stateid *stp; 596327431affSDai Ngo struct nfs4_file *nf; 596427431affSDai Ngo 596527431affSDai Ngo list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) { 596627431affSDai Ngo nf = stp->st_stid.sc_file; 596727431affSDai Ngo ctx = nf->fi_inode->i_flctx; 596827431affSDai Ngo if (!ctx) 596927431affSDai Ngo continue; 597027431affSDai Ngo if (locks_owner_has_blockers(ctx, lo)) 597127431affSDai Ngo return true; 597227431affSDai Ngo } 597327431affSDai Ngo return false; 597427431affSDai Ngo } 597527431affSDai Ngo 597627431affSDai Ngo static bool 597727431affSDai Ngo nfs4_anylock_blockers(struct nfs4_client *clp) 59783d694271SDai Ngo { 59793d694271SDai Ngo int i; 59803d694271SDai Ngo struct nfs4_stateowner *so; 598127431affSDai Ngo struct nfs4_lockowner *lo; 59823d694271SDai Ngo 598327431affSDai Ngo if (atomic_read(&clp->cl_delegs_in_recall)) 598427431affSDai Ngo return true; 59853d694271SDai Ngo spin_lock(&clp->cl_lock); 59863d694271SDai Ngo for (i = 0; i < OWNER_HASH_SIZE; i++) { 59873d694271SDai Ngo list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i], 59883d694271SDai Ngo so_strhash) { 59893d694271SDai Ngo if (so->so_is_open_owner) 59903d694271SDai Ngo continue; 599127431affSDai Ngo lo = lockowner(so); 599227431affSDai Ngo if (nfs4_lockowner_has_blockers(lo)) { 59933d694271SDai Ngo spin_unlock(&clp->cl_lock); 59943d694271SDai Ngo return true; 59953d694271SDai Ngo } 59963d694271SDai Ngo } 59973d694271SDai Ngo } 599827431affSDai Ngo spin_unlock(&clp->cl_lock); 599966af2579SDai Ngo return false; 600066af2579SDai Ngo } 600166af2579SDai Ngo 600266af2579SDai Ngo static void 600366af2579SDai Ngo nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, 600466af2579SDai Ngo struct laundry_time *lt) 600566af2579SDai Ngo { 60064271c2c0SDai Ngo unsigned int maxreap, reapcnt = 0; 600766af2579SDai Ngo struct list_head *pos, *next; 600866af2579SDai Ngo struct nfs4_client *clp; 600966af2579SDai Ngo 60104271c2c0SDai Ngo maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ? 60114271c2c0SDai Ngo NFSD_CLIENT_MAX_TRIM_PER_RUN : 0; 601266af2579SDai Ngo INIT_LIST_HEAD(reaplist); 601366af2579SDai Ngo spin_lock(&nn->client_lock); 601466af2579SDai Ngo list_for_each_safe(pos, next, &nn->client_lru) { 601566af2579SDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 601666af2579SDai Ngo if (clp->cl_state == NFSD4_EXPIRABLE) 601766af2579SDai Ngo goto exp_client; 601866af2579SDai Ngo if (!state_expired(lt, clp->cl_time)) 601966af2579SDai Ngo break; 60203a4ea23dSDai Ngo if (!atomic_read(&clp->cl_rpc_users)) { 60213a4ea23dSDai Ngo if (clp->cl_state == NFSD4_ACTIVE) 60223a4ea23dSDai Ngo atomic_inc(&nn->nfsd_courtesy_clients); 602366af2579SDai Ngo clp->cl_state = NFSD4_COURTESY; 60243a4ea23dSDai Ngo } 60254271c2c0SDai Ngo if (!client_has_state(clp)) 602666af2579SDai Ngo goto exp_client; 60274271c2c0SDai Ngo if (!nfs4_anylock_blockers(clp)) 60284271c2c0SDai Ngo if (reapcnt >= maxreap) 60294271c2c0SDai Ngo continue; 603066af2579SDai Ngo exp_client: 60314271c2c0SDai Ngo if (!mark_client_expired_locked(clp)) { 603266af2579SDai Ngo list_add(&clp->cl_lru, reaplist); 60334271c2c0SDai Ngo reapcnt++; 603466af2579SDai Ngo } 603566af2579SDai Ngo } 603666af2579SDai Ngo spin_unlock(&nn->client_lock); 603766af2579SDai Ngo } 603866af2579SDai Ngo 60397746b32fSDai Ngo static void 60407746b32fSDai Ngo nfs4_get_courtesy_client_reaplist(struct nfsd_net *nn, 60417746b32fSDai Ngo struct list_head *reaplist) 60427746b32fSDai Ngo { 60437746b32fSDai Ngo unsigned int maxreap = 0, reapcnt = 0; 60447746b32fSDai Ngo struct list_head *pos, *next; 60457746b32fSDai Ngo struct nfs4_client *clp; 60467746b32fSDai Ngo 60477746b32fSDai Ngo maxreap = NFSD_CLIENT_MAX_TRIM_PER_RUN; 60487746b32fSDai Ngo INIT_LIST_HEAD(reaplist); 60497746b32fSDai Ngo 60507746b32fSDai Ngo spin_lock(&nn->client_lock); 60517746b32fSDai Ngo list_for_each_safe(pos, next, &nn->client_lru) { 60527746b32fSDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 60537746b32fSDai Ngo if (clp->cl_state == NFSD4_ACTIVE) 60547746b32fSDai Ngo break; 60557746b32fSDai Ngo if (reapcnt >= maxreap) 60567746b32fSDai Ngo break; 60577746b32fSDai Ngo if (!mark_client_expired_locked(clp)) { 60587746b32fSDai Ngo list_add(&clp->cl_lru, reaplist); 60597746b32fSDai Ngo reapcnt++; 60607746b32fSDai Ngo } 60617746b32fSDai Ngo } 60627746b32fSDai Ngo spin_unlock(&nn->client_lock); 60637746b32fSDai Ngo } 60647746b32fSDai Ngo 60657746b32fSDai Ngo static void 60667746b32fSDai Ngo nfs4_process_client_reaplist(struct list_head *reaplist) 60677746b32fSDai Ngo { 60687746b32fSDai Ngo struct list_head *pos, *next; 60697746b32fSDai Ngo struct nfs4_client *clp; 60707746b32fSDai Ngo 60717746b32fSDai Ngo list_for_each_safe(pos, next, reaplist) { 60727746b32fSDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 60737746b32fSDai Ngo trace_nfsd_clid_purged(&clp->cl_clientid); 60747746b32fSDai Ngo list_del_init(&clp->cl_lru); 60757746b32fSDai Ngo expire_client(clp); 60767746b32fSDai Ngo } 60777746b32fSDai Ngo } 60787746b32fSDai Ngo 607920b7d86fSArnd Bergmann static time64_t 608009121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 60811da177e4SLinus Torvalds { 6082fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 60831da177e4SLinus Torvalds struct nfs4_delegation *dp; 6084217526e7SJeff Layton struct nfs4_ol_stateid *stp; 60857919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 60861da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 60877f7e7a40SJ. Bruce Fields struct laundry_time lt = { 60887f7e7a40SJ. Bruce Fields .cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease, 60897f7e7a40SJ. Bruce Fields .new_timeo = nn->nfsd4_lease 60907f7e7a40SJ. Bruce Fields }; 6091624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 6092624322f1SOlga Kornievskaia copy_stateid_t *cps_t; 6093624322f1SOlga Kornievskaia int i; 60941da177e4SLinus Torvalds 609503f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 60967f7e7a40SJ. Bruce Fields lt.new_timeo = 0; 609703f318caSJ. Bruce Fields goto out; 609803f318caSJ. Bruce Fields } 609912760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 6100624322f1SOlga Kornievskaia 6101624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6102624322f1SOlga Kornievskaia idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { 6103624322f1SOlga Kornievskaia cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); 6104781fde1aSChuck Lever if (cps->cp_stateid.cs_type == NFS4_COPYNOTIFY_STID && 61057f7e7a40SJ. Bruce Fields state_expired(<, cps->cpntf_time)) 6106624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 6107624322f1SOlga Kornievskaia } 6108624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 610966af2579SDai Ngo nfs4_get_client_reaplist(nn, &reaplist, <); 61107746b32fSDai Ngo nfs4_process_client_reaplist(&reaplist); 61117746b32fSDai Ngo 6112cdc97505SBenny Halevy spin_lock(&state_lock); 6113e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 61141da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 61157f7e7a40SJ. Bruce Fields if (!state_expired(<, dp->dl_time)) 61161da177e4SLinus Torvalds break; 61173fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 611842690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 61191da177e4SLinus Torvalds } 6120cdc97505SBenny Halevy spin_unlock(&state_lock); 61212d4a532dSJeff Layton while (!list_empty(&reaplist)) { 61222d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 61232d4a532dSJeff Layton dl_recall_lru); 61242d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 61253bd64a5bSJ. Bruce Fields revoke_delegation(dp); 61261da177e4SLinus Torvalds } 6127217526e7SJeff Layton 6128217526e7SJeff Layton spin_lock(&nn->client_lock); 6129217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 6130217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 6131217526e7SJeff Layton oo_close_lru); 61327f7e7a40SJ. Bruce Fields if (!state_expired(<, oo->oo_time)) 61331da177e4SLinus Torvalds break; 6134217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 6135217526e7SJeff Layton stp = oo->oo_last_closed_stid; 6136217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 6137217526e7SJeff Layton spin_unlock(&nn->client_lock); 6138217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 6139217526e7SJeff Layton spin_lock(&nn->client_lock); 61401da177e4SLinus Torvalds } 6141217526e7SJeff Layton spin_unlock(&nn->client_lock); 6142217526e7SJeff Layton 61437919d0a2SJeff Layton /* 61447919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 61457919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 61467919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 61477919d0a2SJeff Layton * under the assumption that the client is no longer interested. 61487919d0a2SJeff Layton * 61497919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 61507919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 61517919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 61527919d0a2SJeff Layton * indefinitely once the lock does become free. 61537919d0a2SJeff Layton */ 61547919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 61550cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 61567919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 61577919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 61587919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 61597f7e7a40SJ. Bruce Fields if (!state_expired(<, nbl->nbl_time)) 61607919d0a2SJeff Layton break; 61617919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 61627919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 61637919d0a2SJeff Layton } 61640cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 61657919d0a2SJeff Layton 61667919d0a2SJeff Layton while (!list_empty(&reaplist)) { 616764ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 61687919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 61697919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 61707919d0a2SJeff Layton free_blocked_lock(nbl); 61717919d0a2SJeff Layton } 6172f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 6173f4e44b39SDai Ngo /* service the server-to-server copy delayed unmount list */ 6174f4e44b39SDai Ngo nfsd4_ssc_expire_umount(nn); 6175f4e44b39SDai Ngo #endif 617603f318caSJ. Bruce Fields out: 61777f7e7a40SJ. Bruce Fields return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 61781da177e4SLinus Torvalds } 61791da177e4SLinus Torvalds 6180a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 6181a254b246SHarvey Harrison 6182a254b246SHarvey Harrison static void 618309121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 61841da177e4SLinus Torvalds { 618520b7d86fSArnd Bergmann time64_t t; 61862e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 618709121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 618809121281SStanislav Kinsbursky laundromat_work); 61891da177e4SLinus Torvalds 619009121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 619109121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 61921da177e4SLinus Torvalds } 61931da177e4SLinus Torvalds 61947746b32fSDai Ngo static void 6195a1049eb4SDai Ngo courtesy_client_reaper(struct nfsd_net *nn) 61967746b32fSDai Ngo { 61977746b32fSDai Ngo struct list_head reaplist; 61987746b32fSDai Ngo 61997746b32fSDai Ngo nfs4_get_courtesy_client_reaplist(nn, &reaplist); 62007746b32fSDai Ngo nfs4_process_client_reaplist(&reaplist); 62017746b32fSDai Ngo } 62027746b32fSDai Ngo 6203a1049eb4SDai Ngo static void 6204*44df6f43SDai Ngo deleg_reaper(struct nfsd_net *nn) 6205*44df6f43SDai Ngo { 6206*44df6f43SDai Ngo struct list_head *pos, *next; 6207*44df6f43SDai Ngo struct nfs4_client *clp; 6208*44df6f43SDai Ngo struct list_head cblist; 6209*44df6f43SDai Ngo 6210*44df6f43SDai Ngo INIT_LIST_HEAD(&cblist); 6211*44df6f43SDai Ngo spin_lock(&nn->client_lock); 6212*44df6f43SDai Ngo list_for_each_safe(pos, next, &nn->client_lru) { 6213*44df6f43SDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 6214*44df6f43SDai Ngo if (clp->cl_state != NFSD4_ACTIVE || 6215*44df6f43SDai Ngo list_empty(&clp->cl_delegations) || 6216*44df6f43SDai Ngo atomic_read(&clp->cl_delegs_in_recall) || 6217*44df6f43SDai Ngo test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) || 6218*44df6f43SDai Ngo (ktime_get_boottime_seconds() - 6219*44df6f43SDai Ngo clp->cl_ra_time < 5)) { 6220*44df6f43SDai Ngo continue; 6221*44df6f43SDai Ngo } 6222*44df6f43SDai Ngo list_add(&clp->cl_ra_cblist, &cblist); 6223*44df6f43SDai Ngo 6224*44df6f43SDai Ngo /* release in nfsd4_cb_recall_any_release */ 6225*44df6f43SDai Ngo atomic_inc(&clp->cl_rpc_users); 6226*44df6f43SDai Ngo set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags); 6227*44df6f43SDai Ngo clp->cl_ra_time = ktime_get_boottime_seconds(); 6228*44df6f43SDai Ngo } 6229*44df6f43SDai Ngo spin_unlock(&nn->client_lock); 6230*44df6f43SDai Ngo 6231*44df6f43SDai Ngo while (!list_empty(&cblist)) { 6232*44df6f43SDai Ngo clp = list_first_entry(&cblist, struct nfs4_client, 6233*44df6f43SDai Ngo cl_ra_cblist); 6234*44df6f43SDai Ngo list_del_init(&clp->cl_ra_cblist); 6235*44df6f43SDai Ngo clp->cl_ra->ra_keep = 0; 6236*44df6f43SDai Ngo clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG); 6237*44df6f43SDai Ngo nfsd4_run_cb(&clp->cl_ra->ra_cb); 6238*44df6f43SDai Ngo } 6239*44df6f43SDai Ngo } 6240*44df6f43SDai Ngo 6241*44df6f43SDai Ngo static void 6242a1049eb4SDai Ngo nfsd4_state_shrinker_worker(struct work_struct *work) 6243a1049eb4SDai Ngo { 6244a1049eb4SDai Ngo struct delayed_work *dwork = to_delayed_work(work); 6245a1049eb4SDai Ngo struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 6246a1049eb4SDai Ngo nfsd_shrinker_work); 6247a1049eb4SDai Ngo 6248a1049eb4SDai Ngo courtesy_client_reaper(nn); 6249*44df6f43SDai Ngo deleg_reaper(nn); 6250a1049eb4SDai Ngo } 6251a1049eb4SDai Ngo 62528fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 6253f8816512SNeilBrown { 62548fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 6255f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 6256f7a4d872SJ. Bruce Fields return nfs_ok; 62571da177e4SLinus Torvalds } 62581da177e4SLinus Torvalds 62591da177e4SLinus Torvalds static 6260dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 62611da177e4SLinus Torvalds { 6262b37ad28bSAl Viro __be32 status = nfserr_openmode; 62631da177e4SLinus Torvalds 626402921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 626502921914SJ. Bruce Fields if (stp->st_openstp) 626602921914SJ. Bruce Fields stp = stp->st_openstp; 626782c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 62681da177e4SLinus Torvalds goto out; 626982c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 62701da177e4SLinus Torvalds goto out; 62711da177e4SLinus Torvalds status = nfs_ok; 62721da177e4SLinus Torvalds out: 62731da177e4SLinus Torvalds return status; 62741da177e4SLinus Torvalds } 62751da177e4SLinus Torvalds 6276b37ad28bSAl Viro static inline __be32 62775ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 62781da177e4SLinus Torvalds { 6279203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 62801da177e4SLinus Torvalds return nfs_ok; 6281c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 628225985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 62831da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 62841da177e4SLinus Torvalds return nfserr_grace; 62851da177e4SLinus Torvalds } else if (flags & WR_STATE) 62861da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 62871da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 62881da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 62891da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 62901da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 62911da177e4SLinus Torvalds } 62921da177e4SLinus Torvalds 629357b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 62940836f587SJ. Bruce Fields { 62956668958fSAndy Adamson /* 62966668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 62976668958fSAndy Adamson * when it is zero. 62986668958fSAndy Adamson */ 629928dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 630081b82965SJ. Bruce Fields return nfs_ok; 630181b82965SJ. Bruce Fields 630281b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 630381b82965SJ. Bruce Fields return nfs_ok; 63046668958fSAndy Adamson 63050836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 630614b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 63070836f587SJ. Bruce Fields return nfserr_bad_stateid; 63080836f587SJ. Bruce Fields /* 630981b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 631081b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 631181b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 631281b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 631381b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 631481b82965SJ. Bruce Fields * but better performance may result in retrying IO that 631581b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 631681b82965SJ. Bruce Fields * reordered in flight: 63170836f587SJ. Bruce Fields */ 63180836f587SJ. Bruce Fields return nfserr_old_stateid; 63190836f587SJ. Bruce Fields } 63200836f587SJ. Bruce Fields 632103da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 632203da3169STrond Myklebust { 632303da3169STrond Myklebust __be32 ret; 632403da3169STrond Myklebust 632503da3169STrond Myklebust spin_lock(&s->sc_lock); 632603da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 632703da3169STrond Myklebust if (ret == nfs_ok) 632803da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 632903da3169STrond Myklebust spin_unlock(&s->sc_lock); 633003da3169STrond Myklebust return ret; 633103da3169STrond Myklebust } 633203da3169STrond Myklebust 6333ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 6334ebe9cb3bSChristoph Hellwig { 6335ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 6336ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 6337ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 6338ebe9cb3bSChristoph Hellwig return nfs_ok; 6339ebe9cb3bSChristoph Hellwig } 6340ebe9cb3bSChristoph Hellwig 63417df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 634217456804SBryan Schumaker { 634397b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 63441af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 634517456804SBryan Schumaker 6346ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 6347ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 63481af71cc8SJeff Layton return status; 6349663e36f0SJ. Bruce Fields if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) 63501af71cc8SJeff Layton return status; 63511af71cc8SJeff Layton spin_lock(&cl->cl_lock); 63521af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 635397b7e3b6SJ. Bruce Fields if (!s) 63541af71cc8SJeff Layton goto out_unlock; 635503da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 635617456804SBryan Schumaker if (status) 63571af71cc8SJeff Layton goto out_unlock; 635823340032SJ. Bruce Fields switch (s->sc_type) { 635923340032SJ. Bruce Fields case NFS4_DELEG_STID: 63601af71cc8SJeff Layton status = nfs_ok; 63611af71cc8SJeff Layton break; 63623bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 63631af71cc8SJeff Layton status = nfserr_deleg_revoked; 63641af71cc8SJeff Layton break; 636523340032SJ. Bruce Fields case NFS4_OPEN_STID: 636623340032SJ. Bruce Fields case NFS4_LOCK_STID: 6367ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 63681af71cc8SJeff Layton break; 636923340032SJ. Bruce Fields default: 637023340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 6371df561f66SGustavo A. R. Silva fallthrough; 637223340032SJ. Bruce Fields case NFS4_CLOSED_STID: 6373b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 63741af71cc8SJeff Layton status = nfserr_bad_stateid; 637523340032SJ. Bruce Fields } 63761af71cc8SJeff Layton out_unlock: 63771af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 63781af71cc8SJeff Layton return status; 637917456804SBryan Schumaker } 638017456804SBryan Schumaker 6381cd61c522SChristoph Hellwig __be32 63822dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 63832dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 63842dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 638538c2f4b1SJ. Bruce Fields { 63860eb6f20aSJ. Bruce Fields __be32 status; 63874d01416aSJeff Layton struct nfs4_stid *stid; 638895da1b3aSAndrew Elble bool return_revoked = false; 638995da1b3aSAndrew Elble 639095da1b3aSAndrew Elble /* 639195da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 639295da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 639395da1b3aSAndrew Elble */ 639495da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 639595da1b3aSAndrew Elble return_revoked = true; 639695da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 639795da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 639838c2f4b1SJ. Bruce Fields 6399ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 6400ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 640138c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 6402f71475baSJ. Bruce Fields status = set_client(&stateid->si_opaque.so_clid, cstate, nn); 6403a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 64044b24ca7dSJeff Layton if (cstate->session) 6405a8a7c677STrond Myklebust return nfserr_bad_stateid; 640638c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 6407a8a7c677STrond Myklebust } 64080eb6f20aSJ. Bruce Fields if (status) 64090eb6f20aSJ. Bruce Fields return status; 64104d01416aSJeff Layton stid = find_stateid_by_type(cstate->clp, stateid, typemask); 64114d01416aSJeff Layton if (!stid) 641238c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 64134d01416aSJeff Layton if ((stid->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 64144d01416aSJeff Layton nfs4_put_stid(stid); 641595da1b3aSAndrew Elble if (cstate->minorversion) 641695da1b3aSAndrew Elble return nfserr_deleg_revoked; 641795da1b3aSAndrew Elble return nfserr_bad_stateid; 641895da1b3aSAndrew Elble } 64194d01416aSJeff Layton *s = stid; 642038c2f4b1SJ. Bruce Fields return nfs_ok; 642138c2f4b1SJ. Bruce Fields } 642238c2f4b1SJ. Bruce Fields 6423eb82dd39SJeff Layton static struct nfsd_file * 6424a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 6425a0649b2dSChristoph Hellwig { 6426af90f707SChristoph Hellwig if (!s) 6427af90f707SChristoph Hellwig return NULL; 6428af90f707SChristoph Hellwig 6429a0649b2dSChristoph Hellwig switch (s->sc_type) { 6430a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 6431a0649b2dSChristoph Hellwig if (WARN_ON_ONCE(!s->sc_file->fi_deleg_file)) 6432a0649b2dSChristoph Hellwig return NULL; 6433eb82dd39SJeff Layton return nfsd_file_get(s->sc_file->fi_deleg_file); 6434a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 6435a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 6436a0649b2dSChristoph Hellwig if (flags & RD_STATE) 6437a0649b2dSChristoph Hellwig return find_readable_file(s->sc_file); 6438a0649b2dSChristoph Hellwig else 6439a0649b2dSChristoph Hellwig return find_writeable_file(s->sc_file); 6440a0649b2dSChristoph Hellwig } 6441a0649b2dSChristoph Hellwig 6442a0649b2dSChristoph Hellwig return NULL; 6443a0649b2dSChristoph Hellwig } 6444a0649b2dSChristoph Hellwig 6445a0649b2dSChristoph Hellwig static __be32 6446d8836f77SJ. Bruce Fields nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) 6447a0649b2dSChristoph Hellwig { 6448a0649b2dSChristoph Hellwig __be32 status; 6449a0649b2dSChristoph Hellwig 6450a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 6451a0649b2dSChristoph Hellwig if (status) 6452a0649b2dSChristoph Hellwig return status; 6453a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 6454a0649b2dSChristoph Hellwig } 6455a0649b2dSChristoph Hellwig 6456af90f707SChristoph Hellwig static __be32 6457af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 64585c4583b2SJeff Layton struct nfsd_file **nfp, int flags) 6459af90f707SChristoph Hellwig { 6460af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 6461eb82dd39SJeff Layton struct nfsd_file *nf; 6462af90f707SChristoph Hellwig __be32 status; 6463af90f707SChristoph Hellwig 6464eb82dd39SJeff Layton nf = nfs4_find_file(s, flags); 6465eb82dd39SJeff Layton if (nf) { 6466af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 6467af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 64685c4583b2SJeff Layton if (status) { 64695c4583b2SJeff Layton nfsd_file_put(nf); 6470eb82dd39SJeff Layton goto out; 64715c4583b2SJeff Layton } 6472af90f707SChristoph Hellwig } else { 6473eb82dd39SJeff Layton status = nfsd_file_acquire(rqstp, fhp, acc, &nf); 6474af90f707SChristoph Hellwig if (status) 6475af90f707SChristoph Hellwig return status; 6476af90f707SChristoph Hellwig } 64775c4583b2SJeff Layton *nfp = nf; 6478eb82dd39SJeff Layton out: 6479eb82dd39SJeff Layton return status; 6480af90f707SChristoph Hellwig } 6481624322f1SOlga Kornievskaia static void 6482624322f1SOlga Kornievskaia _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 6483624322f1SOlga Kornievskaia { 6484781fde1aSChuck Lever WARN_ON_ONCE(cps->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID); 6485781fde1aSChuck Lever if (!refcount_dec_and_test(&cps->cp_stateid.cs_count)) 6486624322f1SOlga Kornievskaia return; 6487624322f1SOlga Kornievskaia list_del(&cps->cp_list); 6488624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 6489781fde1aSChuck Lever cps->cp_stateid.cs_stid.si_opaque.so_id); 6490624322f1SOlga Kornievskaia kfree(cps); 6491624322f1SOlga Kornievskaia } 6492b7342204SOlga Kornievskaia /* 6493b7342204SOlga Kornievskaia * A READ from an inter server to server COPY will have a 6494b7342204SOlga Kornievskaia * copy stateid. Look up the copy notify stateid from the 6495b7342204SOlga Kornievskaia * idr structure and take a reference on it. 6496b7342204SOlga Kornievskaia */ 6497ce0887acSOlga Kornievskaia __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st, 6498ce0887acSOlga Kornievskaia struct nfs4_client *clp, 6499b7342204SOlga Kornievskaia struct nfs4_cpntf_state **cps) 6500b7342204SOlga Kornievskaia { 6501b7342204SOlga Kornievskaia copy_stateid_t *cps_t; 6502b7342204SOlga Kornievskaia struct nfs4_cpntf_state *state = NULL; 6503b7342204SOlga Kornievskaia 6504b7342204SOlga Kornievskaia if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id) 6505b7342204SOlga Kornievskaia return nfserr_bad_stateid; 6506b7342204SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6507b7342204SOlga Kornievskaia cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id); 6508b7342204SOlga Kornievskaia if (cps_t) { 6509b7342204SOlga Kornievskaia state = container_of(cps_t, struct nfs4_cpntf_state, 6510b7342204SOlga Kornievskaia cp_stateid); 6511781fde1aSChuck Lever if (state->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID) { 65125277a79eSDan Carpenter state = NULL; 65135277a79eSDan Carpenter goto unlock; 65145277a79eSDan Carpenter } 6515ce0887acSOlga Kornievskaia if (!clp) 6516781fde1aSChuck Lever refcount_inc(&state->cp_stateid.cs_count); 6517ce0887acSOlga Kornievskaia else 6518ce0887acSOlga Kornievskaia _free_cpntf_state_locked(nn, state); 6519b7342204SOlga Kornievskaia } 65205277a79eSDan Carpenter unlock: 6521b7342204SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 6522b7342204SOlga Kornievskaia if (!state) 6523b7342204SOlga Kornievskaia return nfserr_bad_stateid; 6524ce0887acSOlga Kornievskaia if (!clp && state) 6525b7342204SOlga Kornievskaia *cps = state; 6526b7342204SOlga Kornievskaia return 0; 6527b7342204SOlga Kornievskaia } 6528b7342204SOlga Kornievskaia 6529b7342204SOlga Kornievskaia static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, 6530b7342204SOlga Kornievskaia struct nfs4_stid **stid) 6531b7342204SOlga Kornievskaia { 6532b7342204SOlga Kornievskaia __be32 status; 6533b7342204SOlga Kornievskaia struct nfs4_cpntf_state *cps = NULL; 653447fdb22dSJ. Bruce Fields struct nfs4_client *found; 6535b7342204SOlga Kornievskaia 6536ce0887acSOlga Kornievskaia status = manage_cpntf_state(nn, st, NULL, &cps); 6537b7342204SOlga Kornievskaia if (status) 6538b7342204SOlga Kornievskaia return status; 6539b7342204SOlga Kornievskaia 654020b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 654147fdb22dSJ. Bruce Fields 654247fdb22dSJ. Bruce Fields status = nfserr_expired; 654347fdb22dSJ. Bruce Fields found = lookup_clientid(&cps->cp_p_clid, true, nn); 654447fdb22dSJ. Bruce Fields if (!found) 6545b7342204SOlga Kornievskaia goto out; 654647fdb22dSJ. Bruce Fields 654747fdb22dSJ. Bruce Fields *stid = find_stateid_by_type(found, &cps->cp_p_stateid, 654847fdb22dSJ. Bruce Fields NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID); 654947fdb22dSJ. Bruce Fields if (*stid) 655047fdb22dSJ. Bruce Fields status = nfs_ok; 655147fdb22dSJ. Bruce Fields else 655247fdb22dSJ. Bruce Fields status = nfserr_bad_stateid; 655347fdb22dSJ. Bruce Fields 655447fdb22dSJ. Bruce Fields put_client_renew(found); 6555b7342204SOlga Kornievskaia out: 6556b7342204SOlga Kornievskaia nfs4_put_cpntf_state(nn, cps); 6557b7342204SOlga Kornievskaia return status; 6558b7342204SOlga Kornievskaia } 6559624322f1SOlga Kornievskaia 6560624322f1SOlga Kornievskaia void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 6561624322f1SOlga Kornievskaia { 6562624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6563624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 6564624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 6565624322f1SOlga Kornievskaia } 6566af90f707SChristoph Hellwig 65671da177e4SLinus Torvalds /* 65681da177e4SLinus Torvalds * Checks for stateid operations 65691da177e4SLinus Torvalds */ 6570b37ad28bSAl Viro __be32 6571af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 6572aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 6573624322f1SOlga Kornievskaia stateid_t *stateid, int flags, struct nfsd_file **nfp, 6574624322f1SOlga Kornievskaia struct nfs4_stid **cstid) 65751da177e4SLinus Torvalds { 6576af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 65773320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 6578af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 6579b37ad28bSAl Viro __be32 status; 65801da177e4SLinus Torvalds 65815c4583b2SJeff Layton if (nfp) 65825c4583b2SJeff Layton *nfp = NULL; 65831da177e4SLinus Torvalds 6584af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 6585074b07d9SJ. Bruce Fields if (cstid) 6586074b07d9SJ. Bruce Fields status = nfserr_bad_stateid; 6587074b07d9SJ. Bruce Fields else 6588074b07d9SJ. Bruce Fields status = check_special_stateids(net, fhp, stateid, 6589074b07d9SJ. Bruce Fields flags); 6590af90f707SChristoph Hellwig goto done; 6591af90f707SChristoph Hellwig } 65921da177e4SLinus Torvalds 65932dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 6594db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 65952dd6e458STrond Myklebust &s, nn); 6596b7342204SOlga Kornievskaia if (status == nfserr_bad_stateid) 6597b7342204SOlga Kornievskaia status = find_cpntf_state(nn, stateid, &s); 659838c2f4b1SJ. Bruce Fields if (status) 6599c2d1d6a8STrond Myklebust return status; 660003da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 6601a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 66020c2a498fSJ. Bruce Fields if (status) 66030c2a498fSJ. Bruce Fields goto out; 6604a0649b2dSChristoph Hellwig 6605f7a4d872SJ. Bruce Fields switch (s->sc_type) { 6606f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 6607a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 6608f7a4d872SJ. Bruce Fields break; 6609f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 6610f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 6611d8836f77SJ. Bruce Fields status = nfs4_check_olstateid(openlockstateid(s), flags); 6612f7a4d872SJ. Bruce Fields break; 6613f7a4d872SJ. Bruce Fields default: 661414bcab1aSTrond Myklebust status = nfserr_bad_stateid; 6615a0649b2dSChristoph Hellwig break; 66161da177e4SLinus Torvalds } 66178fcd461dSJeff Layton if (status) 66188fcd461dSJeff Layton goto out; 66198fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 6620a0649b2dSChristoph Hellwig 6621af90f707SChristoph Hellwig done: 66225c4583b2SJeff Layton if (status == nfs_ok && nfp) 66235c4583b2SJeff Layton status = nfs4_check_file(rqstp, fhp, s, nfp, flags); 66241da177e4SLinus Torvalds out: 6625624322f1SOlga Kornievskaia if (s) { 6626624322f1SOlga Kornievskaia if (!status && cstid) 6627624322f1SOlga Kornievskaia *cstid = s; 6628624322f1SOlga Kornievskaia else 6629fd911011STrond Myklebust nfs4_put_stid(s); 6630624322f1SOlga Kornievskaia } 66311da177e4SLinus Torvalds return status; 66321da177e4SLinus Torvalds } 66331da177e4SLinus Torvalds 6634e1ca12dfSBryan Schumaker /* 663517456804SBryan Schumaker * Test if the stateid is valid 663617456804SBryan Schumaker */ 663717456804SBryan Schumaker __be32 663817456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6639eb69853dSChristoph Hellwig union nfsd4_op_u *u) 664017456804SBryan Schumaker { 6641eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 664203cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 6643ec59659bSJ. Bruce Fields struct nfs4_client *cl = cstate->clp; 664403cfb420SBryan Schumaker 664503cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 66467df302f7SChuck Lever stateid->ts_id_status = 66477df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 664803cfb420SBryan Schumaker 664917456804SBryan Schumaker return nfs_ok; 665017456804SBryan Schumaker } 665117456804SBryan Schumaker 665242691398SChuck Lever static __be32 665342691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 665442691398SChuck Lever { 665542691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 665642691398SChuck Lever __be32 ret; 665742691398SChuck Lever 6658659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 6659659aefb6STrond Myklebust if (ret) 6660659aefb6STrond Myklebust goto out_put_stid; 666142691398SChuck Lever 666242691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 666342691398SChuck Lever if (ret) 666442691398SChuck Lever goto out; 666542691398SChuck Lever 666642691398SChuck Lever ret = nfserr_locks_held; 666742691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 666842691398SChuck Lever lockowner(stp->st_stateowner))) 666942691398SChuck Lever goto out; 667042691398SChuck Lever 667142691398SChuck Lever release_lock_stateid(stp); 667242691398SChuck Lever ret = nfs_ok; 667342691398SChuck Lever 667442691398SChuck Lever out: 667542691398SChuck Lever mutex_unlock(&stp->st_mutex); 6676659aefb6STrond Myklebust out_put_stid: 667742691398SChuck Lever nfs4_put_stid(s); 667842691398SChuck Lever return ret; 667942691398SChuck Lever } 668042691398SChuck Lever 6681e1ca12dfSBryan Schumaker __be32 6682e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6683eb69853dSChristoph Hellwig union nfsd4_op_u *u) 6684e1ca12dfSBryan Schumaker { 6685eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 6686e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 66872da1cec7SJ. Bruce Fields struct nfs4_stid *s; 66883bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 6689ec59659bSJ. Bruce Fields struct nfs4_client *cl = cstate->clp; 66902da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 6691e1ca12dfSBryan Schumaker 66921af71cc8SJeff Layton spin_lock(&cl->cl_lock); 66931af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 66942da1cec7SJ. Bruce Fields if (!s) 66951af71cc8SJeff Layton goto out_unlock; 669603da3169STrond Myklebust spin_lock(&s->sc_lock); 66972da1cec7SJ. Bruce Fields switch (s->sc_type) { 66982da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 6699e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 67001af71cc8SJeff Layton break; 67012da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 67021af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 67031af71cc8SJeff Layton if (ret) 67041af71cc8SJeff Layton break; 67051af71cc8SJeff Layton ret = nfserr_locks_held; 67061af71cc8SJeff Layton break; 67072da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 670803da3169STrond Myklebust spin_unlock(&s->sc_lock); 6709a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 67101af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 671142691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 67121af71cc8SJeff Layton goto out; 67133bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 671403da3169STrond Myklebust spin_unlock(&s->sc_lock); 67153bd64a5bSJ. Bruce Fields dp = delegstateid(s); 67162d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 67172d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 67186011695dSTrond Myklebust nfs4_put_stid(s); 67193bd64a5bSJ. Bruce Fields ret = nfs_ok; 67201af71cc8SJeff Layton goto out; 67211af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 6722e1ca12dfSBryan Schumaker } 672303da3169STrond Myklebust spin_unlock(&s->sc_lock); 67241af71cc8SJeff Layton out_unlock: 67251af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 6726e1ca12dfSBryan Schumaker out: 6727e1ca12dfSBryan Schumaker return ret; 6728e1ca12dfSBryan Schumaker } 6729e1ca12dfSBryan Schumaker 67304c4cd222SNeilBrown static inline int 67314c4cd222SNeilBrown setlkflg (int type) 67324c4cd222SNeilBrown { 67334c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 67344c4cd222SNeilBrown RD_STATE : WR_STATE; 67354c4cd222SNeilBrown } 67361da177e4SLinus Torvalds 6737dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 6738c0a5d93eSJ. Bruce Fields { 6739c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 6740c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 6741c0a5d93eSJ. Bruce Fields __be32 status; 6742c0a5d93eSJ. Bruce Fields 6743c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 6744c0a5d93eSJ. Bruce Fields if (status) 6745c0a5d93eSJ. Bruce Fields return status; 67469271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 67479271d7e5STrond Myklebust if (status != nfs_ok) 67489271d7e5STrond Myklebust return status; 6749f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 675035a92fe8SJeff Layton if (status == nfs_ok) 675135a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 675235a92fe8SJeff Layton if (status != nfs_ok) 6753feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6754f7a4d872SJ. Bruce Fields return status; 6755c0a5d93eSJ. Bruce Fields } 6756c0a5d93eSJ. Bruce Fields 67571da177e4SLinus Torvalds /* 67581da177e4SLinus Torvalds * Checks for sequence id mutating operations. 67591da177e4SLinus Torvalds */ 6760b37ad28bSAl Viro static __be32 6761dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 67622288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 67633320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 67643320fef1SStanislav Kinsbursky struct nfsd_net *nn) 67651da177e4SLinus Torvalds { 67660836f587SJ. Bruce Fields __be32 status; 676738c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6768e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 67691da177e4SLinus Torvalds 6770dd5e3fbcSChuck Lever trace_nfsd_preprocess(seqid, stateid); 67711da177e4SLinus Torvalds 67721da177e4SLinus Torvalds *stpp = NULL; 67732dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 6774c0a5d93eSJ. Bruce Fields if (status) 6775c0a5d93eSJ. Bruce Fields return status; 6776e17f99b7STrond Myklebust stp = openlockstateid(s); 677758fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 67781da177e4SLinus Torvalds 6779e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 6780fd911011STrond Myklebust if (!status) 6781e17f99b7STrond Myklebust *stpp = stp; 6782fd911011STrond Myklebust else 6783fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 6784e17f99b7STrond Myklebust return status; 67851da177e4SLinus Torvalds } 67861da177e4SLinus Torvalds 67873320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 67883320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 6789c0a5d93eSJ. Bruce Fields { 6790c0a5d93eSJ. Bruce Fields __be32 status; 6791c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 67924cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 67931da177e4SLinus Torvalds 6794c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 67954cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 67960836f587SJ. Bruce Fields if (status) 67970836f587SJ. Bruce Fields return status; 67984cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 67994cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 6800feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 68014cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 6802c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 68034cbfc9f7STrond Myklebust } 68044cbfc9f7STrond Myklebust *stpp = stp; 68053a4f98bbSNeilBrown return nfs_ok; 68061da177e4SLinus Torvalds } 68071da177e4SLinus Torvalds 6808b37ad28bSAl Viro __be32 6809ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6810eb69853dSChristoph Hellwig union nfsd4_op_u *u) 68111da177e4SLinus Torvalds { 6812eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 6813b37ad28bSAl Viro __be32 status; 6814fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 6815dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 68163320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 68171da177e4SLinus Torvalds 6818a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 6819a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 68201da177e4SLinus Torvalds 6821ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 6822a8cddc5dSJ. Bruce Fields if (status) 6823a8cddc5dSJ. Bruce Fields return status; 68241da177e4SLinus Torvalds 68259072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 6826ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 68273320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 68289072d5c6SJ. Bruce Fields if (status) 68291da177e4SLinus Torvalds goto out; 6830fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 683168b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 683235a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 6833feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 68342585fc79STrond Myklebust goto put_stateid; 683535a92fe8SJeff Layton } 6836dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 68379767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 6838feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6839dd5e3fbcSChuck Lever trace_nfsd_open_confirm(oc->oc_seqid, &stp->st_stid.sc_stateid); 68402a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 684168b66e82SJ. Bruce Fields status = nfs_ok; 68422585fc79STrond Myklebust put_stateid: 68432585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 68441da177e4SLinus Torvalds out: 68459411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 68461da177e4SLinus Torvalds return status; 68471da177e4SLinus Torvalds } 68481da177e4SLinus Torvalds 68496409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 68501da177e4SLinus Torvalds { 685182c5ff1bSJeff Layton if (!test_access(access, stp)) 68526409a5a6SJ. Bruce Fields return; 685311b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 685482c5ff1bSJeff Layton clear_access(access, stp); 6855f197c271SJ. Bruce Fields } 68566409a5a6SJ. Bruce Fields 68576409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 68586409a5a6SJ. Bruce Fields { 68596409a5a6SJ. Bruce Fields switch (to_access) { 68606409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 68616409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 68626409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 68636409a5a6SJ. Bruce Fields break; 68646409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 68656409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 68666409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 68676409a5a6SJ. Bruce Fields break; 68686409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 68696409a5a6SJ. Bruce Fields break; 68706409a5a6SJ. Bruce Fields default: 6871063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 68721da177e4SLinus Torvalds } 68731da177e4SLinus Torvalds } 68741da177e4SLinus Torvalds 6875b37ad28bSAl Viro __be32 6876ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 6877eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 68781da177e4SLinus Torvalds { 6879eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 6880b37ad28bSAl Viro __be32 status; 6881dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 68823320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 68831da177e4SLinus Torvalds 6884a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 6885a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 68861da177e4SLinus Torvalds 6887c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 68882c8bd7e0SBenny Halevy if (od->od_deleg_want) 68892c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 68902c8bd7e0SBenny Halevy od->od_deleg_want); 68911da177e4SLinus Torvalds 6892c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 68933320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 68949072d5c6SJ. Bruce Fields if (status) 68951da177e4SLinus Torvalds goto out; 68961da177e4SLinus Torvalds status = nfserr_inval; 689782c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 6898c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 68991da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 69000667b1e9STrond Myklebust goto put_stateid; 69011da177e4SLinus Torvalds } 6902ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 6903c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 69041da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 69050667b1e9STrond Myklebust goto put_stateid; 69061da177e4SLinus Torvalds } 69076409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 6908ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 69099767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 69101da177e4SLinus Torvalds status = nfs_ok; 69110667b1e9STrond Myklebust put_stateid: 6912feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 69130667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 69141da177e4SLinus Torvalds out: 69159411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 69161da177e4SLinus Torvalds return status; 69171da177e4SLinus Torvalds } 69181da177e4SLinus Torvalds 6919f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 6920f7a4d872SJ. Bruce Fields { 6921acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 6922e8568739SJeff Layton bool unhashed; 6923d83017f9SJeff Layton LIST_HEAD(reaplist); 6924019805feSDai Ngo struct nfs4_ol_stateid *stp; 6925acf9295bSTrond Myklebust 69262c41beb0SJeff Layton spin_lock(&clp->cl_lock); 6927e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 6928acf9295bSTrond Myklebust 6929d83017f9SJeff Layton if (clp->cl_minorversion) { 6930e8568739SJeff Layton if (unhashed) 6931d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 6932d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6933019805feSDai Ngo list_for_each_entry(stp, &reaplist, st_locks) 6934019805feSDai Ngo nfs4_free_cpntf_statelist(clp->net, &stp->st_stid); 6935d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6936d83017f9SJeff Layton } else { 6937d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6938d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6939e8568739SJeff Layton if (unhashed) 6940d3134b10SJeff Layton move_to_close_lru(s, clp->net); 694138c387b5SJ. Bruce Fields } 6942d83017f9SJeff Layton } 694338c387b5SJ. Bruce Fields 69441da177e4SLinus Torvalds /* 69451da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 69461da177e4SLinus Torvalds */ 6947b37ad28bSAl Viro __be32 6948ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6949eb69853dSChristoph Hellwig union nfsd4_op_u *u) 69501da177e4SLinus Torvalds { 6951eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 6952b37ad28bSAl Viro __be32 status; 6953dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 69543320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 69553320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 69561da177e4SLinus Torvalds 6957a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 6958a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 69591da177e4SLinus Torvalds 6960f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 6961f7a4d872SJ. Bruce Fields &close->cl_stateid, 6962f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 69633320fef1SStanislav Kinsbursky &stp, nn); 69649411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 69659072d5c6SJ. Bruce Fields if (status) 69661da177e4SLinus Torvalds goto out; 696715ca08d3STrond Myklebust 696815ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 6969bd2decacSJeff Layton 6970bd2decacSJeff Layton /* 6971bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 6972bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 6973bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 6974bd2decacSJeff Layton * that racing ops see that there was a state change. 6975bd2decacSJeff Layton */ 69769767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 69771da177e4SLinus Torvalds 6978f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 697915ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 69808a0b589dSTrond Myklebust 6981bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 6982bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 6983bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 6984bd2decacSJeff Layton * universally. 6985bd2decacSJeff Layton * 6986bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 6987bd2decacSJeff Layton */ 6988bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 6989fb500a7cSTrond Myklebust 69908a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 69918a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 69921da177e4SLinus Torvalds out: 69931da177e4SLinus Torvalds return status; 69941da177e4SLinus Torvalds } 69951da177e4SLinus Torvalds 6996b37ad28bSAl Viro __be32 6997ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6998eb69853dSChristoph Hellwig union nfsd4_op_u *u) 69991da177e4SLinus Torvalds { 7000eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 7001203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 7002203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 700338c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 7004b37ad28bSAl Viro __be32 status; 70053320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 70061da177e4SLinus Torvalds 7007ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 7008203a8c8eSJ. Bruce Fields return status; 70091da177e4SLinus Torvalds 70102dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 701138c2f4b1SJ. Bruce Fields if (status) 7012203a8c8eSJ. Bruce Fields goto out; 701338c2f4b1SJ. Bruce Fields dp = delegstateid(s); 701403da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 7015203a8c8eSJ. Bruce Fields if (status) 7016fd911011STrond Myklebust goto put_stateid; 7017203a8c8eSJ. Bruce Fields 701820eee313SChuck Lever trace_nfsd_deleg_return(stateid); 7019c035362eSChuck Lever wake_up_var(d_inode(cstate->current_fh.fh_dentry)); 70203bd64a5bSJ. Bruce Fields destroy_delegation(dp); 7021fd911011STrond Myklebust put_stateid: 7022fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 70231da177e4SLinus Torvalds out: 70241da177e4SLinus Torvalds return status; 70251da177e4SLinus Torvalds } 70261da177e4SLinus Torvalds 702787df4de8SBenny Halevy /* last octet in a range */ 702887df4de8SBenny Halevy static inline u64 702987df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 703087df4de8SBenny Halevy { 703187df4de8SBenny Halevy u64 end; 703287df4de8SBenny Halevy 7033063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 703487df4de8SBenny Halevy end = start + len; 703587df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 703687df4de8SBenny Halevy } 703787df4de8SBenny Halevy 70381da177e4SLinus Torvalds /* 70391da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 70401da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 70411da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 70421da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 70431da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 70441da177e4SLinus Torvalds * the VFS, but this is a very deep change! 70451da177e4SLinus Torvalds */ 70461da177e4SLinus Torvalds static inline void 70471da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 70481da177e4SLinus Torvalds { 70491da177e4SLinus Torvalds if (lock->fl_start < 0) 70501da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 70511da177e4SLinus Torvalds if (lock->fl_end < 0) 70521da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 70531da177e4SLinus Torvalds } 70541da177e4SLinus Torvalds 7055cae80b30SJeff Layton static fl_owner_t 705635aff067SChuck Lever nfsd4_lm_get_owner(fl_owner_t owner) 7057aef9583bSKinglong Mee { 7058cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 7059cae80b30SJeff Layton 7060cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 7061cae80b30SJeff Layton return owner; 7062aef9583bSKinglong Mee } 7063aef9583bSKinglong Mee 7064cae80b30SJeff Layton static void 706535aff067SChuck Lever nfsd4_lm_put_owner(fl_owner_t owner) 7066aef9583bSKinglong Mee { 7067cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 7068aef9583bSKinglong Mee 7069cae80b30SJeff Layton if (lo) 7070aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 7071aef9583bSKinglong Mee } 7072aef9583bSKinglong Mee 707327431affSDai Ngo /* return pointer to struct nfs4_client if client is expirable */ 707427431affSDai Ngo static bool 707527431affSDai Ngo nfsd4_lm_lock_expirable(struct file_lock *cfl) 707627431affSDai Ngo { 707727431affSDai Ngo struct nfs4_lockowner *lo = (struct nfs4_lockowner *)cfl->fl_owner; 707827431affSDai Ngo struct nfs4_client *clp = lo->lo_owner.so_client; 707927431affSDai Ngo struct nfsd_net *nn; 708027431affSDai Ngo 708127431affSDai Ngo if (try_to_expire_client(clp)) { 708227431affSDai Ngo nn = net_generic(clp->net, nfsd_net_id); 708327431affSDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 708427431affSDai Ngo return true; 708527431affSDai Ngo } 708627431affSDai Ngo return false; 708727431affSDai Ngo } 708827431affSDai Ngo 708927431affSDai Ngo /* schedule laundromat to run immediately and wait for it to complete */ 709027431affSDai Ngo static void 709127431affSDai Ngo nfsd4_lm_expire_lock(void) 709227431affSDai Ngo { 709327431affSDai Ngo flush_workqueue(laundry_wq); 709427431affSDai Ngo } 709527431affSDai Ngo 709676d348faSJeff Layton static void 709776d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 709876d348faSJeff Layton { 709976d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 710076d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 710176d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 710276d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 710376d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 710476d348faSJeff Layton bool queue = false; 710576d348faSJeff Layton 71067919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 71070cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 710876d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 710976d348faSJeff Layton list_del_init(&nbl->nbl_list); 71107919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 711176d348faSJeff Layton queue = true; 711276d348faSJeff Layton } 71130cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 711476d348faSJeff Layton 71152cde7f81SChuck Lever if (queue) { 71162cde7f81SChuck Lever trace_nfsd_cb_notify_lock(lo, nbl); 711776d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 711876d348faSJeff Layton } 71192cde7f81SChuck Lever } 712076d348faSJeff Layton 71217b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 712227431affSDai Ngo .lm_mod_owner = THIS_MODULE, 712376d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 712435aff067SChuck Lever .lm_get_owner = nfsd4_lm_get_owner, 712535aff067SChuck Lever .lm_put_owner = nfsd4_lm_put_owner, 712627431affSDai Ngo .lm_lock_expirable = nfsd4_lm_lock_expirable, 712727431affSDai Ngo .lm_expire_lock = nfsd4_lm_expire_lock, 7128d5b9026aSNeilBrown }; 71291da177e4SLinus Torvalds 71301da177e4SLinus Torvalds static inline void 71311da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 71321da177e4SLinus Torvalds { 7133fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 71341da177e4SLinus Torvalds 7135d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 7136fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 71376f4859b8SJ. Bruce Fields xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner, 71386f4859b8SJ. Bruce Fields GFP_KERNEL); 71397c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 71407c13f344SJ. Bruce Fields /* We just don't care that much */ 71417c13f344SJ. Bruce Fields goto nevermind; 7142fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 7143d5b9026aSNeilBrown } else { 71447c13f344SJ. Bruce Fields nevermind: 71457c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 71467c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 7147d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 7148d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 71491da177e4SLinus Torvalds } 71501da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 715187df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 715287df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 71531da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 71541da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 71551da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 71561da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 71571da177e4SLinus Torvalds } 71581da177e4SLinus Torvalds 7159fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 7160c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 71611da177e4SLinus Torvalds { 7162d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 7163b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 71641da177e4SLinus Torvalds 71650a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 71660a880a28STrond Myklebust 7167d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 7168d4f0489fSTrond Myklebust so_strhash) { 7169b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 7170b3c32bcdSTrond Myklebust continue; 7171b5971afaSKinglong Mee if (same_owner_str(so, owner)) 7172b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 71731da177e4SLinus Torvalds } 71741da177e4SLinus Torvalds return NULL; 71751da177e4SLinus Torvalds } 71761da177e4SLinus Torvalds 7177c58c6610STrond Myklebust static struct nfs4_lockowner * 7178c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 7179c58c6610STrond Myklebust { 7180c58c6610STrond Myklebust struct nfs4_lockowner *lo; 7181c58c6610STrond Myklebust 7182d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7183c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 7184d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 7185c58c6610STrond Myklebust return lo; 7186c58c6610STrond Myklebust } 7187c58c6610STrond Myklebust 71888f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 71898f4b54c5SJeff Layton { 7190c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 71918f4b54c5SJeff Layton } 71928f4b54c5SJeff Layton 71936b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 71946b180f0bSJeff Layton { 71956b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 71966b180f0bSJeff Layton 71976b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 71986b180f0bSJeff Layton } 71996b180f0bSJeff Layton 72006b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 72018f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 72026b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 72036b180f0bSJeff Layton }; 72046b180f0bSJeff Layton 72051da177e4SLinus Torvalds /* 72061da177e4SLinus Torvalds * Alloc a lock owner structure. 72071da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 720825985edcSLucas De Marchi * occurred. 72091da177e4SLinus Torvalds * 721016bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 72111da177e4SLinus Torvalds */ 7212fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 7213c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 7214c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 7215c58c6610STrond Myklebust struct nfsd4_lock *lock) 7216c58c6610STrond Myklebust { 7217c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 72181da177e4SLinus Torvalds 7219fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 7220fe0750e5SJ. Bruce Fields if (!lo) 72211da177e4SLinus Torvalds return NULL; 722276d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 7223fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 7224fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 72255db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 72266b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 7227d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7228c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 7229c58c6610STrond Myklebust if (ret == NULL) { 7230c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 7231d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 7232c58c6610STrond Myklebust ret = lo; 7233c58c6610STrond Myklebust } else 7234d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 7235d50ffdedSKinglong Mee 7236d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 7237340f0ba1SJ. Bruce Fields return ret; 72381da177e4SLinus Torvalds } 72391da177e4SLinus Torvalds 7240fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 7241a451b123STrond Myklebust find_lock_stateid(const struct nfs4_lockowner *lo, 7242a451b123STrond Myklebust const struct nfs4_ol_stateid *ost) 7243fd1fd685STrond Myklebust { 7244fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 7245fd1fd685STrond Myklebust 7246a451b123STrond Myklebust lockdep_assert_held(&ost->st_stid.sc_client->cl_lock); 7247fd1fd685STrond Myklebust 7248a451b123STrond Myklebust /* If ost is not hashed, ost->st_locks will not be valid */ 7249a451b123STrond Myklebust if (!nfs4_ol_stateid_unhashed(ost)) 7250a451b123STrond Myklebust list_for_each_entry(lst, &ost->st_locks, st_locks) { 7251a451b123STrond Myklebust if (lst->st_stateowner == &lo->lo_owner) { 7252fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 7253fd1fd685STrond Myklebust return lst; 7254fd1fd685STrond Myklebust } 7255fd1fd685STrond Myklebust } 7256fd1fd685STrond Myklebust return NULL; 7257fd1fd685STrond Myklebust } 7258fd1fd685STrond Myklebust 7259beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 7260356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 7261356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 7262f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 72631da177e4SLinus Torvalds { 7264d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 7265beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 72661da177e4SLinus Torvalds 7267beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 72684f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 7269beeca19cSTrond Myklebust retry: 7270beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 7271a451b123STrond Myklebust if (nfs4_ol_stateid_unhashed(open_stp)) 7272a451b123STrond Myklebust goto out_close; 7273a451b123STrond Myklebust retstp = find_lock_stateid(lo, open_stp); 7274beeca19cSTrond Myklebust if (retstp) 7275a451b123STrond Myklebust goto out_found; 7276a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 72773abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 7278b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 727913cd2184SNeilBrown get_nfs4_file(fp); 728011b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 72810997b173SJ. Bruce Fields stp->st_access_bmap = 0; 72821da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 72834c4cd222SNeilBrown stp->st_openstp = open_stp; 7284a451b123STrond Myklebust spin_lock(&fp->fi_lock); 72853c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 72861c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 72871d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 72881d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 7289beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 7290a451b123STrond Myklebust return stp; 7291a451b123STrond Myklebust out_found: 7292a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 7293beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 7294beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 7295beeca19cSTrond Myklebust goto retry; 7296beeca19cSTrond Myklebust } 7297beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 7298beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 7299a451b123STrond Myklebust return retstp; 7300a451b123STrond Myklebust out_close: 7301a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 7302a451b123STrond Myklebust mutex_unlock(&stp->st_mutex); 7303a451b123STrond Myklebust return NULL; 73041da177e4SLinus Torvalds } 73051da177e4SLinus Torvalds 7306c53530daSJeff Layton static struct nfs4_ol_stateid * 7307356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 7308356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 7309356a95ecSJeff Layton bool *new) 7310356a95ecSJeff Layton { 7311356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 7312356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 7313356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 7314356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 7315356a95ecSJeff Layton 7316beeca19cSTrond Myklebust *new = false; 7317356a95ecSJeff Layton spin_lock(&clp->cl_lock); 7318a451b123STrond Myklebust lst = find_lock_stateid(lo, ost); 7319356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 7320beeca19cSTrond Myklebust if (lst != NULL) { 7321beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 7322beeca19cSTrond Myklebust goto out; 7323beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 7324beeca19cSTrond Myklebust } 7325d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 7326356a95ecSJeff Layton if (ns == NULL) 7327356a95ecSJeff Layton return NULL; 7328356a95ecSJeff Layton 7329beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 7330beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 7331356a95ecSJeff Layton *new = true; 7332beeca19cSTrond Myklebust else 7333356a95ecSJeff Layton nfs4_put_stid(ns); 7334beeca19cSTrond Myklebust out: 7335356a95ecSJeff Layton return lst; 7336356a95ecSJeff Layton } 7337c53530daSJeff Layton 7338fd39ca9aSNeilBrown static int 73391da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 73401da177e4SLinus Torvalds { 734187df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 7342e7969315SKinglong Mee (length > ~offset))); 73431da177e4SLinus Torvalds } 73441da177e4SLinus Torvalds 7345dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 73460997b173SJ. Bruce Fields { 734711b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 73480997b173SJ. Bruce Fields 73497214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 73507214e860SJeff Layton 735182c5ff1bSJeff Layton if (test_access(access, lock_stp)) 73520997b173SJ. Bruce Fields return; 735312659651SJeff Layton __nfs4_file_get_access(fp, access); 735482c5ff1bSJeff Layton set_access(access, lock_stp); 73550997b173SJ. Bruce Fields } 73560997b173SJ. Bruce Fields 7357356a95ecSJeff Layton static __be32 7358356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 7359356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 7360356a95ecSJeff Layton struct nfsd4_lock *lock, 7361dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 736264a284d0SJ. Bruce Fields { 73635db1c03fSJeff Layton __be32 status; 736411b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 736564a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 736664a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 73672b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 736864a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 7369dd257933SJeff Layton struct nfs4_ol_stateid *lst; 737064a284d0SJ. Bruce Fields unsigned int strhashval; 737164a284d0SJ. Bruce Fields 7372c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 7373c53530daSJeff Layton if (!lo) { 737476f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 737564a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 737664a284d0SJ. Bruce Fields if (lo == NULL) 737764a284d0SJ. Bruce Fields return nfserr_jukebox; 7378c53530daSJeff Layton } else { 7379c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 73805db1c03fSJeff Layton status = nfserr_bad_seqid; 7381c53530daSJeff Layton if (!cstate->minorversion && 7382c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 73835db1c03fSJeff Layton goto out; 7384c53530daSJeff Layton } 7385c53530daSJeff Layton 7386dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 7387dd257933SJeff Layton if (lst == NULL) { 73885db1c03fSJeff Layton status = nfserr_jukebox; 73895db1c03fSJeff Layton goto out; 739064a284d0SJ. Bruce Fields } 7391dd257933SJeff Layton 73925db1c03fSJeff Layton status = nfs_ok; 7393dd257933SJeff Layton *plst = lst; 73945db1c03fSJeff Layton out: 73955db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 73965db1c03fSJeff Layton return status; 739764a284d0SJ. Bruce Fields } 739864a284d0SJ. Bruce Fields 73991da177e4SLinus Torvalds /* 74001da177e4SLinus Torvalds * LOCK operation 74011da177e4SLinus Torvalds */ 7402b37ad28bSAl Viro __be32 7403ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7404eb69853dSChristoph Hellwig union nfsd4_op_u *u) 74051da177e4SLinus Torvalds { 7406eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 7407fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 7408fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 74093d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 74100667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 74117214e860SJeff Layton struct nfs4_file *fp; 7412eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 741376d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 741421179d81SJeff Layton struct file_lock *file_lock = NULL; 741521179d81SJeff Layton struct file_lock *conflock = NULL; 7416b37ad28bSAl Viro __be32 status = 0; 7417b34f27aaSJ. Bruce Fields int lkflg; 7418b8dd7b9aSAl Viro int err; 74195db1c03fSJeff Layton bool new = false; 742076d348faSJeff Layton unsigned char fl_type; 742176d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 74223320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 74233320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 74241da177e4SLinus Torvalds 74251da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 74261da177e4SLinus Torvalds (long long) lock->lk_offset, 74271da177e4SLinus Torvalds (long long) lock->lk_length); 74281da177e4SLinus Torvalds 74291da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 74301da177e4SLinus Torvalds return nfserr_inval; 74311da177e4SLinus Torvalds 7432ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 74338837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 7434a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 7435a6f6ef2fSAndy Adamson return status; 7436a6f6ef2fSAndy Adamson } 7437a6f6ef2fSAndy Adamson 74381da177e4SLinus Torvalds if (lock->lk_is_new) { 7439684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 7440684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 744176f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 7442ec59659bSJ. Bruce Fields &cstate->clp->cl_clientid, 7443684e5638SJ. Bruce Fields sizeof(clientid_t)); 7444684e5638SJ. Bruce Fields 74451da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 7446c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 74471da177e4SLinus Torvalds lock->lk_new_open_seqid, 74481da177e4SLinus Torvalds &lock->lk_new_open_stateid, 74493320fef1SStanislav Kinsbursky &open_stp, nn); 745037515177SNeilBrown if (status) 74511da177e4SLinus Torvalds goto out; 7452feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 7453fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 7454b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 7455684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 745676f6c9e1SKinglong Mee &lock->lk_new_clientid)) 7457b34f27aaSJ. Bruce Fields goto out; 745864a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 74595db1c03fSJeff Layton &lock_stp, &new); 74603d0fabd5STrond Myklebust } else { 7461dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 74621da177e4SLinus Torvalds lock->lk_old_lock_seqid, 74631da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 74643320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 74653d0fabd5STrond Myklebust } 74661da177e4SLinus Torvalds if (status) 74671da177e4SLinus Torvalds goto out; 7468fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 74691da177e4SLinus Torvalds 7470b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 7471b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 7472b34f27aaSJ. Bruce Fields if (status) 7473b34f27aaSJ. Bruce Fields goto out; 7474b34f27aaSJ. Bruce Fields 74750dd395dcSNeilBrown status = nfserr_grace; 74763320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 74770dd395dcSNeilBrown goto out; 74780dd395dcSNeilBrown status = nfserr_no_grace; 74793320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 74800dd395dcSNeilBrown goto out; 74810dd395dcSNeilBrown 7482bb0a55bbSJ. Bruce Fields if (lock->lk_reclaim) 7483bb0a55bbSJ. Bruce Fields fl_flags |= FL_RECLAIM; 7484bb0a55bbSJ. Bruce Fields 748511b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 74861da177e4SLinus Torvalds switch (lock->lk_type) { 74871da177e4SLinus Torvalds case NFS4_READW_LT: 748840595cdcSJ. Bruce Fields if (nfsd4_has_session(cstate)) 748976d348faSJeff Layton fl_flags |= FL_SLEEP; 7490df561f66SGustavo A. R. Silva fallthrough; 749176d348faSJeff Layton case NFS4_READ_LT: 74927214e860SJeff Layton spin_lock(&fp->fi_lock); 7493eb82dd39SJeff Layton nf = find_readable_file_locked(fp); 7494eb82dd39SJeff Layton if (nf) 74950997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 74967214e860SJeff Layton spin_unlock(&fp->fi_lock); 749776d348faSJeff Layton fl_type = F_RDLCK; 74981da177e4SLinus Torvalds break; 74991da177e4SLinus Torvalds case NFS4_WRITEW_LT: 750040595cdcSJ. Bruce Fields if (nfsd4_has_session(cstate)) 750176d348faSJeff Layton fl_flags |= FL_SLEEP; 7502df561f66SGustavo A. R. Silva fallthrough; 750376d348faSJeff Layton case NFS4_WRITE_LT: 75047214e860SJeff Layton spin_lock(&fp->fi_lock); 7505eb82dd39SJeff Layton nf = find_writeable_file_locked(fp); 7506eb82dd39SJeff Layton if (nf) 75070997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 75087214e860SJeff Layton spin_unlock(&fp->fi_lock); 750976d348faSJeff Layton fl_type = F_WRLCK; 75101da177e4SLinus Torvalds break; 75111da177e4SLinus Torvalds default: 75121da177e4SLinus Torvalds status = nfserr_inval; 75131da177e4SLinus Torvalds goto out; 75141da177e4SLinus Torvalds } 751576d348faSJeff Layton 7516eb82dd39SJeff Layton if (!nf) { 7517f9d7562fSJ. Bruce Fields status = nfserr_openmode; 7518f9d7562fSJ. Bruce Fields goto out; 7519f9d7562fSJ. Bruce Fields } 7520aef9583bSKinglong Mee 752140595cdcSJ. Bruce Fields /* 752240595cdcSJ. Bruce Fields * Most filesystems with their own ->lock operations will block 752340595cdcSJ. Bruce Fields * the nfsd thread waiting to acquire the lock. That leads to 752440595cdcSJ. Bruce Fields * deadlocks (we don't want every nfsd thread tied up waiting 752540595cdcSJ. Bruce Fields * for file locks), so don't attempt blocking lock notifications 752640595cdcSJ. Bruce Fields * on those filesystems: 752740595cdcSJ. Bruce Fields */ 752840595cdcSJ. Bruce Fields if (nf->nf_file->f_op->lock) 752940595cdcSJ. Bruce Fields fl_flags &= ~FL_SLEEP; 753040595cdcSJ. Bruce Fields 753176d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 753276d348faSJeff Layton if (!nbl) { 753376d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 753476d348faSJeff Layton status = nfserr_jukebox; 753576d348faSJeff Layton goto out; 753676d348faSJeff Layton } 753776d348faSJeff Layton 753876d348faSJeff Layton file_lock = &nbl->nbl_lock; 753976d348faSJeff Layton file_lock->fl_type = fl_type; 7540aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 754121179d81SJeff Layton file_lock->fl_pid = current->tgid; 7542eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 754376d348faSJeff Layton file_lock->fl_flags = fl_flags; 754421179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 754521179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 754621179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 754721179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 75481da177e4SLinus Torvalds 754921179d81SJeff Layton conflock = locks_alloc_lock(); 755021179d81SJeff Layton if (!conflock) { 755121179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 755221179d81SJeff Layton status = nfserr_jukebox; 755321179d81SJeff Layton goto out; 755421179d81SJeff Layton } 75551da177e4SLinus Torvalds 755676d348faSJeff Layton if (fl_flags & FL_SLEEP) { 755720b7d86fSArnd Bergmann nbl->nbl_time = ktime_get_boottime_seconds(); 75580cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 755976d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 75607919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 756147446d74SVasily Averin kref_get(&nbl->nbl_kref); 75620cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 756376d348faSJeff Layton } 756476d348faSJeff Layton 7565eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, conflock); 756676d348faSJeff Layton switch (err) { 75671da177e4SLinus Torvalds case 0: /* success! */ 75689767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 7569b8dd7b9aSAl Viro status = 0; 757003f318caSJ. Bruce Fields if (lock->lk_reclaim) 757103f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 7572eb76b3fdSAndy Adamson break; 757376d348faSJeff Layton case FILE_LOCK_DEFERRED: 757447446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 757576d348faSJeff Layton nbl = NULL; 7576df561f66SGustavo A. R. Silva fallthrough; 757776d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 7578eb76b3fdSAndy Adamson status = nfserr_denied; 7579eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 758021179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 7581eb76b3fdSAndy Adamson break; 758276d348faSJeff Layton case -EDEADLK: 75831da177e4SLinus Torvalds status = nfserr_deadlock; 7584eb76b3fdSAndy Adamson break; 75851da177e4SLinus Torvalds default: 7586fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 75873e772463SJ. Bruce Fields status = nfserrno(err); 7588eb76b3fdSAndy Adamson break; 75891da177e4SLinus Torvalds } 75901da177e4SLinus Torvalds out: 759176d348faSJeff Layton if (nbl) { 759276d348faSJeff Layton /* dequeue it if we queued it before */ 759376d348faSJeff Layton if (fl_flags & FL_SLEEP) { 75940cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 759547446d74SVasily Averin if (!list_empty(&nbl->nbl_list) && 759647446d74SVasily Averin !list_empty(&nbl->nbl_lru)) { 759776d348faSJeff Layton list_del_init(&nbl->nbl_list); 75987919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 759947446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 760047446d74SVasily Averin } 760147446d74SVasily Averin /* nbl can use one of lists to be linked to reaplist */ 76020cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 760376d348faSJeff Layton } 760476d348faSJeff Layton free_blocked_lock(nbl); 760576d348faSJeff Layton } 7606eb82dd39SJeff Layton if (nf) 7607eb82dd39SJeff Layton nfsd_file_put(nf); 76085db1c03fSJeff Layton if (lock_stp) { 76095db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 76105db1c03fSJeff Layton if (cstate->replay_owner && 76115db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 76125db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 76135db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 76145db1c03fSJeff Layton 76155db1c03fSJeff Layton /* 76165db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 76175db1c03fSJeff Layton * returning an error, then just go ahead and release it. 76185db1c03fSJeff Layton */ 761925020720SJ. Bruce Fields if (status && new) 76205db1c03fSJeff Layton release_lock_stateid(lock_stp); 7621beeca19cSTrond Myklebust 7622beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 76235db1c03fSJeff Layton 76243d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 76255db1c03fSJeff Layton } 76260667b1e9STrond Myklebust if (open_stp) 76270667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 76289411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 762921179d81SJeff Layton if (conflock) 763021179d81SJeff Layton locks_free_lock(conflock); 76311da177e4SLinus Torvalds return status; 76321da177e4SLinus Torvalds } 76331da177e4SLinus Torvalds 76341da177e4SLinus Torvalds /* 763555ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 763655ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 76370bcc7ca4SJ. Bruce Fields * vfs_test_lock. 763855ef1274SJ. Bruce Fields */ 763904da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 764055ef1274SJ. Bruce Fields { 76416b556ca2SJeff Layton struct nfsd_file *nf; 7642bb4d53d6SNeilBrown struct inode *inode; 7643217fd6f6SJ. Bruce Fields __be32 err; 7644217fd6f6SJ. Bruce Fields 7645217fd6f6SJ. Bruce Fields err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); 7646217fd6f6SJ. Bruce Fields if (err) 7647217fd6f6SJ. Bruce Fields return err; 7648bb4d53d6SNeilBrown inode = fhp->fh_dentry->d_inode; 7649bb4d53d6SNeilBrown inode_lock(inode); /* to block new leases till after test_lock: */ 7650bb4d53d6SNeilBrown err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); 7651217fd6f6SJ. Bruce Fields if (err) 7652217fd6f6SJ. Bruce Fields goto out; 76530bcc7ca4SJ. Bruce Fields lock->fl_file = nf->nf_file; 76546b556ca2SJeff Layton err = nfserrno(vfs_test_lock(nf->nf_file, lock)); 76550bcc7ca4SJ. Bruce Fields lock->fl_file = NULL; 7656217fd6f6SJ. Bruce Fields out: 7657bb4d53d6SNeilBrown inode_unlock(inode); 76586b556ca2SJeff Layton nfsd_file_put(nf); 765955ef1274SJ. Bruce Fields return err; 766055ef1274SJ. Bruce Fields } 766155ef1274SJ. Bruce Fields 766255ef1274SJ. Bruce Fields /* 76631da177e4SLinus Torvalds * LOCKT operation 76641da177e4SLinus Torvalds */ 7665b37ad28bSAl Viro __be32 7666ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7667eb69853dSChristoph Hellwig union nfsd4_op_u *u) 76681da177e4SLinus Torvalds { 7669eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 767021179d81SJeff Layton struct file_lock *file_lock = NULL; 76715db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 7672b37ad28bSAl Viro __be32 status; 76737f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 76741da177e4SLinus Torvalds 76755ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 76761da177e4SLinus Torvalds return nfserr_grace; 76771da177e4SLinus Torvalds 76781da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 76791da177e4SLinus Torvalds return nfserr_inval; 76801da177e4SLinus Torvalds 76819b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 7682f71475baSJ. Bruce Fields status = set_client(&lockt->lt_clientid, cstate, nn); 76839b2ef62bSJ. Bruce Fields if (status) 76841da177e4SLinus Torvalds goto out; 76859b2ef62bSJ. Bruce Fields } 76861da177e4SLinus Torvalds 768775c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 76881da177e4SLinus Torvalds goto out; 76891da177e4SLinus Torvalds 769021179d81SJeff Layton file_lock = locks_alloc_lock(); 769121179d81SJeff Layton if (!file_lock) { 769221179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 769321179d81SJeff Layton status = nfserr_jukebox; 769421179d81SJeff Layton goto out; 769521179d81SJeff Layton } 76966cd90662SKinglong Mee 76971da177e4SLinus Torvalds switch (lockt->lt_type) { 76981da177e4SLinus Torvalds case NFS4_READ_LT: 76991da177e4SLinus Torvalds case NFS4_READW_LT: 770021179d81SJeff Layton file_lock->fl_type = F_RDLCK; 77011da177e4SLinus Torvalds break; 77021da177e4SLinus Torvalds case NFS4_WRITE_LT: 77031da177e4SLinus Torvalds case NFS4_WRITEW_LT: 770421179d81SJeff Layton file_lock->fl_type = F_WRLCK; 77051da177e4SLinus Torvalds break; 77061da177e4SLinus Torvalds default: 77072fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 77081da177e4SLinus Torvalds status = nfserr_inval; 77091da177e4SLinus Torvalds goto out; 77101da177e4SLinus Torvalds } 77111da177e4SLinus Torvalds 7712c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 7713fe0750e5SJ. Bruce Fields if (lo) 771421179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 771521179d81SJeff Layton file_lock->fl_pid = current->tgid; 771621179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 77171da177e4SLinus Torvalds 771821179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 771921179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 77201da177e4SLinus Torvalds 772121179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 77221da177e4SLinus Torvalds 772321179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 772404da6e9dSAl Viro if (status) 7725fd85b817SMarc Eshel goto out; 772604da6e9dSAl Viro 772721179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 77281da177e4SLinus Torvalds status = nfserr_denied; 772921179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 77301da177e4SLinus Torvalds } 77311da177e4SLinus Torvalds out: 77325db1c03fSJeff Layton if (lo) 77335db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 773421179d81SJeff Layton if (file_lock) 773521179d81SJeff Layton locks_free_lock(file_lock); 77361da177e4SLinus Torvalds return status; 77371da177e4SLinus Torvalds } 77381da177e4SLinus Torvalds 7739b37ad28bSAl Viro __be32 7740ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7741eb69853dSChristoph Hellwig union nfsd4_op_u *u) 77421da177e4SLinus Torvalds { 7743eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 7744dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 7745eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 774621179d81SJeff Layton struct file_lock *file_lock = NULL; 7747b37ad28bSAl Viro __be32 status; 7748b8dd7b9aSAl Viro int err; 77493320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 77501da177e4SLinus Torvalds 77511da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 77521da177e4SLinus Torvalds (long long) locku->lu_offset, 77531da177e4SLinus Torvalds (long long) locku->lu_length); 77541da177e4SLinus Torvalds 77551da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 77561da177e4SLinus Torvalds return nfserr_inval; 77571da177e4SLinus Torvalds 77589072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 77593320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 77603320fef1SStanislav Kinsbursky &stp, nn); 77619072d5c6SJ. Bruce Fields if (status) 77621da177e4SLinus Torvalds goto out; 7763eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 7764eb82dd39SJeff Layton if (!nf) { 7765f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 7766858cc573STrond Myklebust goto put_stateid; 7767f9d7562fSJ. Bruce Fields } 776821179d81SJeff Layton file_lock = locks_alloc_lock(); 776921179d81SJeff Layton if (!file_lock) { 777021179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 777121179d81SJeff Layton status = nfserr_jukebox; 7772eb82dd39SJeff Layton goto put_file; 777321179d81SJeff Layton } 77746cd90662SKinglong Mee 777521179d81SJeff Layton file_lock->fl_type = F_UNLCK; 7776aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 777721179d81SJeff Layton file_lock->fl_pid = current->tgid; 7778eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 777921179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 778021179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 778121179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 77821da177e4SLinus Torvalds 778321179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 778421179d81SJeff Layton locku->lu_length); 778521179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 77861da177e4SLinus Torvalds 7787eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, NULL); 7788b8dd7b9aSAl Viro if (err) { 7789fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 77901da177e4SLinus Torvalds goto out_nfserr; 77911da177e4SLinus Torvalds } 77929767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 7793eb82dd39SJeff Layton put_file: 7794eb82dd39SJeff Layton nfsd_file_put(nf); 7795858cc573STrond Myklebust put_stateid: 7796feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 7797858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 77981da177e4SLinus Torvalds out: 77999411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 780021179d81SJeff Layton if (file_lock) 780121179d81SJeff Layton locks_free_lock(file_lock); 78021da177e4SLinus Torvalds return status; 78031da177e4SLinus Torvalds 78041da177e4SLinus Torvalds out_nfserr: 7805b8dd7b9aSAl Viro status = nfserrno(err); 7806eb82dd39SJeff Layton goto put_file; 78071da177e4SLinus Torvalds } 78081da177e4SLinus Torvalds 78091da177e4SLinus Torvalds /* 78101da177e4SLinus Torvalds * returns 7811f9c00c3aSJeff Layton * true: locks held by lockowner 7812f9c00c3aSJeff Layton * false: no locks held by lockowner 78131da177e4SLinus Torvalds */ 7814f9c00c3aSJeff Layton static bool 7815f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 78161da177e4SLinus Torvalds { 7817bd61e0a9SJeff Layton struct file_lock *fl; 7818f9c00c3aSJeff Layton int status = false; 7819eb82dd39SJeff Layton struct nfsd_file *nf = find_any_file(fp); 7820f9c00c3aSJeff Layton struct inode *inode; 7821bd61e0a9SJeff Layton struct file_lock_context *flctx; 7822f9c00c3aSJeff Layton 7823eb82dd39SJeff Layton if (!nf) { 7824f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 7825f9c00c3aSJeff Layton WARN_ON_ONCE(1); 7826f9c00c3aSJeff Layton return status; 7827f9c00c3aSJeff Layton } 7828f9c00c3aSJeff Layton 7829eb82dd39SJeff Layton inode = locks_inode(nf->nf_file); 7830bd61e0a9SJeff Layton flctx = inode->i_flctx; 78311da177e4SLinus Torvalds 7832bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 78336109c850SJeff Layton spin_lock(&flctx->flc_lock); 7834bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 7835bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 7836f9c00c3aSJeff Layton status = true; 7837f9c00c3aSJeff Layton break; 78381da177e4SLinus Torvalds } 7839796dadfdSJ. Bruce Fields } 78406109c850SJeff Layton spin_unlock(&flctx->flc_lock); 7841bd61e0a9SJeff Layton } 7842eb82dd39SJeff Layton nfsd_file_put(nf); 78431da177e4SLinus Torvalds return status; 78441da177e4SLinus Torvalds } 78451da177e4SLinus Torvalds 7846043862b0SChuck Lever /** 7847043862b0SChuck Lever * nfsd4_release_lockowner - process NFSv4.0 RELEASE_LOCKOWNER operations 7848043862b0SChuck Lever * @rqstp: RPC transaction 7849043862b0SChuck Lever * @cstate: NFSv4 COMPOUND state 7850043862b0SChuck Lever * @u: RELEASE_LOCKOWNER arguments 7851043862b0SChuck Lever * 7852043862b0SChuck Lever * The lockowner's so_count is bumped when a lock record is added 7853043862b0SChuck Lever * or when copying a conflicting lock. The latter case is brief, 7854043862b0SChuck Lever * but can lead to fleeting false positives when looking for 7855043862b0SChuck Lever * locks-in-use. 7856043862b0SChuck Lever * 7857043862b0SChuck Lever * Return values: 7858043862b0SChuck Lever * %nfs_ok: lockowner released or not found 7859043862b0SChuck Lever * %nfserr_locks_held: lockowner still in use 7860043862b0SChuck Lever * %nfserr_stale_clientid: clientid no longer active 7861043862b0SChuck Lever * %nfserr_expired: clientid not recognized 7862043862b0SChuck Lever */ 7863b37ad28bSAl Viro __be32 7864b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 7865b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 7866eb69853dSChristoph Hellwig union nfsd4_op_u *u) 78671da177e4SLinus Torvalds { 7868eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 78697f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 7870bd8fdb6eSChuck Lever clientid_t *clid = &rlockowner->rl_clientid; 7871bd8fdb6eSChuck Lever struct nfs4_ol_stateid *stp; 7872bd8fdb6eSChuck Lever struct nfs4_lockowner *lo; 7873c58c6610STrond Myklebust struct nfs4_client *clp; 787488584818SChuck Lever LIST_HEAD(reaplist); 7875bd8fdb6eSChuck Lever __be32 status; 78761da177e4SLinus Torvalds 78771da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 78781da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 78791da177e4SLinus Torvalds 7880f71475baSJ. Bruce Fields status = set_client(clid, cstate, nn); 78819b2ef62bSJ. Bruce Fields if (status) 788251f5e783STrond Myklebust return status; 7883d4f0489fSTrond Myklebust clp = cstate->clp; 7884bd8fdb6eSChuck Lever 7885d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7886bd8fdb6eSChuck Lever lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner); 788788584818SChuck Lever if (!lo) { 7888d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 7889043862b0SChuck Lever return nfs_ok; 789088584818SChuck Lever } 7891bd8fdb6eSChuck Lever if (atomic_read(&lo->lo_owner.so_count) != 2) { 7892bd8fdb6eSChuck Lever spin_unlock(&clp->cl_lock); 7893bd8fdb6eSChuck Lever nfs4_put_stateowner(&lo->lo_owner); 7894bd8fdb6eSChuck Lever return nfserr_locks_held; 7895bd8fdb6eSChuck Lever } 789688584818SChuck Lever unhash_lockowner_locked(lo); 789788584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 789888584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 789988584818SChuck Lever struct nfs4_ol_stateid, 790088584818SChuck Lever st_perstateowner); 790188584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 790288584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 790388584818SChuck Lever } 790488584818SChuck Lever spin_unlock(&clp->cl_lock); 7905043862b0SChuck Lever 790688584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 790768ef3bc3SJeff Layton remove_blocked_locks(lo); 790888584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 7909043862b0SChuck Lever return nfs_ok; 79101da177e4SLinus Torvalds } 79111da177e4SLinus Torvalds 79121da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 7913a55370a3SNeilBrown alloc_reclaim(void) 79141da177e4SLinus Torvalds { 7915a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 79161da177e4SLinus Torvalds } 79171da177e4SLinus Torvalds 79180ce0c2b5SJeff Layton bool 79196b189105SScott Mayhew nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) 7920c7b9a459SNeilBrown { 79210ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 7922c7b9a459SNeilBrown 792352e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 79240ce0c2b5SJeff Layton return (crp && crp->cr_clp); 7925c7b9a459SNeilBrown } 7926c7b9a459SNeilBrown 79271da177e4SLinus Torvalds /* 79281da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 79296b189105SScott Mayhew * 79306b189105SScott Mayhew * The caller is responsible for freeing name.data if NULL is returned (it 79316b189105SScott Mayhew * will be freed in nfs4_remove_reclaim_record in the normal case). 79321da177e4SLinus Torvalds */ 7933772a9bbbSJeff Layton struct nfs4_client_reclaim * 79346ee95d1cSScott Mayhew nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, 79356ee95d1cSScott Mayhew struct nfsd_net *nn) 79361da177e4SLinus Torvalds { 79371da177e4SLinus Torvalds unsigned int strhashval; 7938772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 79391da177e4SLinus Torvalds 7940a55370a3SNeilBrown crp = alloc_reclaim(); 7941772a9bbbSJeff Layton if (crp) { 7942a55370a3SNeilBrown strhashval = clientstr_hashval(name); 79431da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 794452e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 79456b189105SScott Mayhew crp->cr_name.data = name.data; 79466b189105SScott Mayhew crp->cr_name.len = name.len; 79476ee95d1cSScott Mayhew crp->cr_princhash.data = princhash.data; 79486ee95d1cSScott Mayhew crp->cr_princhash.len = princhash.len; 79490ce0c2b5SJeff Layton crp->cr_clp = NULL; 795052e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 7951772a9bbbSJeff Layton } 7952772a9bbbSJeff Layton return crp; 79531da177e4SLinus Torvalds } 79541da177e4SLinus Torvalds 79552a4317c5SJeff Layton void 795652e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 7957ce30e539SJeff Layton { 7958ce30e539SJeff Layton list_del(&crp->cr_strhash); 79596b189105SScott Mayhew kfree(crp->cr_name.data); 79606ee95d1cSScott Mayhew kfree(crp->cr_princhash.data); 7961ce30e539SJeff Layton kfree(crp); 796252e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 7963ce30e539SJeff Layton } 7964ce30e539SJeff Layton 7965ce30e539SJeff Layton void 796652e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 79671da177e4SLinus Torvalds { 79681da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 79691da177e4SLinus Torvalds int i; 79701da177e4SLinus Torvalds 79711da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 797252e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 797352e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 79741da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 797552e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 79761da177e4SLinus Torvalds } 79771da177e4SLinus Torvalds } 7978063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 79791da177e4SLinus Torvalds } 79801da177e4SLinus Torvalds 79811da177e4SLinus Torvalds /* 79821da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 79832a4317c5SJeff Layton struct nfs4_client_reclaim * 79846b189105SScott Mayhew nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) 79851da177e4SLinus Torvalds { 79861da177e4SLinus Torvalds unsigned int strhashval; 79871da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 79881da177e4SLinus Torvalds 79896b189105SScott Mayhew strhashval = clientstr_hashval(name); 799052e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 79916b189105SScott Mayhew if (compare_blob(&crp->cr_name, &name) == 0) { 79921da177e4SLinus Torvalds return crp; 79931da177e4SLinus Torvalds } 79941da177e4SLinus Torvalds } 79951da177e4SLinus Torvalds return NULL; 79961da177e4SLinus Torvalds } 79971da177e4SLinus Torvalds 7998b37ad28bSAl Viro __be32 79991722b046SJ. Bruce Fields nfs4_check_open_reclaim(struct nfs4_client *clp) 80001da177e4SLinus Torvalds { 80011722b046SJ. Bruce Fields if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) 80023b3e7b72SJeff Layton return nfserr_no_grace; 80033b3e7b72SJeff Layton 80041722b046SJ. Bruce Fields if (nfsd4_client_record_check(clp)) 80050fe492dbSTrond Myklebust return nfserr_reclaim_bad; 80060fe492dbSTrond Myklebust 80070fe492dbSTrond Myklebust return nfs_ok; 80081da177e4SLinus Torvalds } 80091da177e4SLinus Torvalds 8010c2f1a551SMeelap Shah /* 8011c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 8012c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 8013c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 8014c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 8015c2f1a551SMeelap Shah * 8016c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 8017c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 8018c2f1a551SMeelap Shah */ 8019c2f1a551SMeelap Shah static void 8020c2f1a551SMeelap Shah set_max_delegations(void) 8021c2f1a551SMeelap Shah { 8022c2f1a551SMeelap Shah /* 8023c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 8024c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 8025c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 8026c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 8027c2f1a551SMeelap Shah */ 8028c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 8029c2f1a551SMeelap Shah } 8030c2f1a551SMeelap Shah 8031d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 80328daae4dcSStanislav Kinsbursky { 80338daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 80348daae4dcSStanislav Kinsbursky int i; 80358daae4dcSStanislav Kinsbursky 80366da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 80376da2ec56SKees Cook sizeof(struct list_head), 80386da2ec56SKees Cook GFP_KERNEL); 80398daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 8040382a62e7SStanislav Kinsbursky goto err; 80416da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 80426da2ec56SKees Cook sizeof(struct list_head), 80436da2ec56SKees Cook GFP_KERNEL); 80440a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 80450a7ec377SStanislav Kinsbursky goto err_unconf_id; 80466da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 80476da2ec56SKees Cook sizeof(struct list_head), 80486da2ec56SKees Cook GFP_KERNEL); 80491872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 80501872de0eSStanislav Kinsbursky goto err_sessionid; 80518daae4dcSStanislav Kinsbursky 8052382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 80538daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 80540a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 8055382a62e7SStanislav Kinsbursky } 80561872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 80571872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 8058382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 8059a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 80609cc76801SArnd Bergmann nn->boot_time = ktime_get_real_seconds(); 806181833de1SVasily Averin nn->grace_ended = false; 806281833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 806381833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 80645ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 806573758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 8066e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 8067c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 8068e0639dc5SOlga Kornievskaia spin_lock_init(&nn->s2s_cp_lock); 8069e0639dc5SOlga Kornievskaia idr_init(&nn->s2s_cp_stateids); 80708daae4dcSStanislav Kinsbursky 80710cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 80720cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 80730cc11a61SJeff Layton 807409121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 8075a1049eb4SDai Ngo INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker); 8076d85ed443SStanislav Kinsbursky get_net(net); 807709121281SStanislav Kinsbursky 80788daae4dcSStanislav Kinsbursky return 0; 8079382a62e7SStanislav Kinsbursky 80801872de0eSStanislav Kinsbursky err_sessionid: 80819b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 80820a7ec377SStanislav Kinsbursky err_unconf_id: 80830a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 8084382a62e7SStanislav Kinsbursky err: 8085382a62e7SStanislav Kinsbursky return -ENOMEM; 80868daae4dcSStanislav Kinsbursky } 80878daae4dcSStanislav Kinsbursky 80888daae4dcSStanislav Kinsbursky static void 80894dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 80908daae4dcSStanislav Kinsbursky { 80918daae4dcSStanislav Kinsbursky int i; 80928daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 80938daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 80948daae4dcSStanislav Kinsbursky 80958daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 80968daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 80978daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 80988daae4dcSStanislav Kinsbursky destroy_client(clp); 80998daae4dcSStanislav Kinsbursky } 81008daae4dcSStanislav Kinsbursky } 8101a99454aaSStanislav Kinsbursky 810268ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 810368ef3bc3SJeff Layton 81042b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 81052b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 81062b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 8107a99454aaSStanislav Kinsbursky destroy_client(clp); 8108a99454aaSStanislav Kinsbursky } 81092b905635SKinglong Mee } 8110a99454aaSStanislav Kinsbursky 81111872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 81120a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 81138daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 81144dce0ac9SStanislav Kinsbursky put_net(net); 81158daae4dcSStanislav Kinsbursky } 81168daae4dcSStanislav Kinsbursky 8117f252bc68SStanislav Kinsbursky int 8118d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 8119ac4d8ff2SNeilBrown { 81205e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 8121b5a1a81eSJ. Bruce Fields int ret; 8122b5a1a81eSJ. Bruce Fields 8123c6c7f2a8STrond Myklebust ret = nfs4_state_create_net(net); 81248daae4dcSStanislav Kinsbursky if (ret) 81258daae4dcSStanislav Kinsbursky return ret; 8126d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 8127d4318acdSJeff Layton nfsd4_client_tracking_init(net); 8128362063a5SScott Mayhew if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) 8129362063a5SScott Mayhew goto skip_grace; 813020b7d86fSArnd Bergmann printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", 81317e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 8132dd5e3fbcSChuck Lever trace_nfsd_grace_start(nn); 81335284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 8134d85ed443SStanislav Kinsbursky return 0; 8135362063a5SScott Mayhew 8136362063a5SScott Mayhew skip_grace: 8137362063a5SScott Mayhew printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n", 8138362063a5SScott Mayhew net->ns.inum); 8139362063a5SScott Mayhew queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ); 8140362063a5SScott Mayhew nfsd4_end_grace(nn); 8141362063a5SScott Mayhew return 0; 8142a6d6b781SJeff Layton } 8143d85ed443SStanislav Kinsbursky 8144d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 8145d85ed443SStanislav Kinsbursky 8146d85ed443SStanislav Kinsbursky int 8147d85ed443SStanislav Kinsbursky nfs4_state_start(void) 8148d85ed443SStanislav Kinsbursky { 8149d85ed443SStanislav Kinsbursky int ret; 8150d85ed443SStanislav Kinsbursky 8151d47b295eSChuck Lever ret = rhltable_init(&nfs4_file_rhltable, &nfs4_file_rhash_params); 8152b5a1a81eSJ. Bruce Fields if (ret) 8153d76cc46bSDai Ngo return ret; 815409121281SStanislav Kinsbursky 8155d47b295eSChuck Lever ret = nfsd4_create_callback_queue(); 8156d47b295eSChuck Lever if (ret) { 8157d47b295eSChuck Lever rhltable_destroy(&nfs4_file_rhltable); 8158d47b295eSChuck Lever return ret; 8159d47b295eSChuck Lever } 8160d47b295eSChuck Lever 8161c2f1a551SMeelap Shah set_max_delegations(); 8162b5a1a81eSJ. Bruce Fields return 0; 81631da177e4SLinus Torvalds } 81641da177e4SLinus Torvalds 8165f252bc68SStanislav Kinsbursky void 81664dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 81671da177e4SLinus Torvalds { 81681da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 81691da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 81704dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 81711da177e4SLinus Torvalds 81724dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 81734dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 8174ac55fdc4SJeff Layton 81751da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 8176cdc97505SBenny Halevy spin_lock(&state_lock); 8177e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 81781da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 81793fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 818042690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 81811da177e4SLinus Torvalds } 8182cdc97505SBenny Halevy spin_unlock(&state_lock); 81831da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 81841da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 818542690676SJeff Layton list_del_init(&dp->dl_recall_lru); 81860af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 81871da177e4SLinus Torvalds } 81881da177e4SLinus Torvalds 81893320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 81904dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 8191d47b295eSChuck Lever rhltable_destroy(&nfs4_file_rhltable); 8192f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 8193f4e44b39SDai Ngo nfsd4_ssc_shutdown_umount(nn); 8194f4e44b39SDai Ngo #endif 81951da177e4SLinus Torvalds } 81961da177e4SLinus Torvalds 81971da177e4SLinus Torvalds void 81981da177e4SLinus Torvalds nfs4_state_shutdown(void) 81991da177e4SLinus Torvalds { 8200c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 82011da177e4SLinus Torvalds } 82028b70484cSTigran Mkrtchyan 82038b70484cSTigran Mkrtchyan static void 82048b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 82058b70484cSTigran Mkrtchyan { 820651100d2bSOlga Kornievskaia if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) && 820751100d2bSOlga Kornievskaia CURRENT_STATEID(stateid)) 820837c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 82098b70484cSTigran Mkrtchyan } 82108b70484cSTigran Mkrtchyan 82118b70484cSTigran Mkrtchyan static void 82128b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 82138b70484cSTigran Mkrtchyan { 821437c593c5STigran Mkrtchyan if (cstate->minorversion) { 821537c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 821651100d2bSOlga Kornievskaia SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 821737c593c5STigran Mkrtchyan } 821837c593c5STigran Mkrtchyan } 821937c593c5STigran Mkrtchyan 822037c593c5STigran Mkrtchyan void 822137c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 822237c593c5STigran Mkrtchyan { 822351100d2bSOlga Kornievskaia CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 82248b70484cSTigran Mkrtchyan } 82258b70484cSTigran Mkrtchyan 822662cd4a59STigran Mkrtchyan /* 822762cd4a59STigran Mkrtchyan * functions to set current state id 822862cd4a59STigran Mkrtchyan */ 82298b70484cSTigran Mkrtchyan void 8230b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 8231b60e9859SChristoph Hellwig union nfsd4_op_u *u) 82329428fe1aSTigran Mkrtchyan { 8233b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 82349428fe1aSTigran Mkrtchyan } 82359428fe1aSTigran Mkrtchyan 82369428fe1aSTigran Mkrtchyan void 8237b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 8238b60e9859SChristoph Hellwig union nfsd4_op_u *u) 82398b70484cSTigran Mkrtchyan { 8240b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 82418b70484cSTigran Mkrtchyan } 82428b70484cSTigran Mkrtchyan 82438b70484cSTigran Mkrtchyan void 8244b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 8245b60e9859SChristoph Hellwig union nfsd4_op_u *u) 824662cd4a59STigran Mkrtchyan { 8247b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 824862cd4a59STigran Mkrtchyan } 824962cd4a59STigran Mkrtchyan 825062cd4a59STigran Mkrtchyan void 8251b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 8252b60e9859SChristoph Hellwig union nfsd4_op_u *u) 825362cd4a59STigran Mkrtchyan { 8254b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 825562cd4a59STigran Mkrtchyan } 825662cd4a59STigran Mkrtchyan 825762cd4a59STigran Mkrtchyan /* 825862cd4a59STigran Mkrtchyan * functions to consume current state id 825962cd4a59STigran Mkrtchyan */ 82601e97b519STigran Mkrtchyan 82611e97b519STigran Mkrtchyan void 826257832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 826357832e7bSChristoph Hellwig union nfsd4_op_u *u) 82649428fe1aSTigran Mkrtchyan { 826557832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 82669428fe1aSTigran Mkrtchyan } 82679428fe1aSTigran Mkrtchyan 82689428fe1aSTigran Mkrtchyan void 826957832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 827057832e7bSChristoph Hellwig union nfsd4_op_u *u) 82719428fe1aSTigran Mkrtchyan { 827257832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 82739428fe1aSTigran Mkrtchyan } 82749428fe1aSTigran Mkrtchyan 82759428fe1aSTigran Mkrtchyan void 827657832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 827757832e7bSChristoph Hellwig union nfsd4_op_u *u) 82781e97b519STigran Mkrtchyan { 827957832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 82801e97b519STigran Mkrtchyan } 82811e97b519STigran Mkrtchyan 82821e97b519STigran Mkrtchyan void 828357832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 828457832e7bSChristoph Hellwig union nfsd4_op_u *u) 82851e97b519STigran Mkrtchyan { 828657832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 82871e97b519STigran Mkrtchyan } 82881e97b519STigran Mkrtchyan 828962cd4a59STigran Mkrtchyan void 829057832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 829157832e7bSChristoph Hellwig union nfsd4_op_u *u) 82928b70484cSTigran Mkrtchyan { 829357832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 82948b70484cSTigran Mkrtchyan } 82958b70484cSTigran Mkrtchyan 82968b70484cSTigran Mkrtchyan void 829757832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 829857832e7bSChristoph Hellwig union nfsd4_op_u *u) 82998b70484cSTigran Mkrtchyan { 830057832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 83018b70484cSTigran Mkrtchyan } 830230813e27STigran Mkrtchyan 830330813e27STigran Mkrtchyan void 830457832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 830557832e7bSChristoph Hellwig union nfsd4_op_u *u) 830630813e27STigran Mkrtchyan { 830757832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 830830813e27STigran Mkrtchyan } 830930813e27STigran Mkrtchyan 831030813e27STigran Mkrtchyan void 831157832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 831257832e7bSChristoph Hellwig union nfsd4_op_u *u) 831330813e27STigran Mkrtchyan { 831457832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 831530813e27STigran Mkrtchyan } 8316