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 find_writeable_file_locked(struct nfs4_file *f) 604de18643dSTrond Myklebust { 605eb82dd39SJeff Layton struct nfsd_file *ret; 606de18643dSTrond Myklebust 607de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 608de18643dSTrond Myklebust 609edd2f552SJeff Layton ret = nfsd_file_get(f->fi_fds[O_WRONLY]); 610de18643dSTrond Myklebust if (!ret) 611edd2f552SJeff Layton ret = nfsd_file_get(f->fi_fds[O_RDWR]); 612de18643dSTrond Myklebust return ret; 613de18643dSTrond Myklebust } 614de18643dSTrond Myklebust 615eb82dd39SJeff Layton static struct nfsd_file * 616de18643dSTrond Myklebust find_writeable_file(struct nfs4_file *f) 617de18643dSTrond Myklebust { 618eb82dd39SJeff Layton struct nfsd_file *ret; 619de18643dSTrond Myklebust 620de18643dSTrond Myklebust spin_lock(&f->fi_lock); 621de18643dSTrond Myklebust ret = find_writeable_file_locked(f); 622de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 623de18643dSTrond Myklebust 624de18643dSTrond Myklebust return ret; 625de18643dSTrond Myklebust } 626de18643dSTrond Myklebust 627eb82dd39SJeff Layton static struct nfsd_file * 628eb82dd39SJeff Layton find_readable_file_locked(struct nfs4_file *f) 629de18643dSTrond Myklebust { 630eb82dd39SJeff Layton struct nfsd_file *ret; 631de18643dSTrond Myklebust 632de18643dSTrond Myklebust lockdep_assert_held(&f->fi_lock); 633de18643dSTrond Myklebust 634edd2f552SJeff Layton ret = nfsd_file_get(f->fi_fds[O_RDONLY]); 635de18643dSTrond Myklebust if (!ret) 636edd2f552SJeff Layton ret = nfsd_file_get(f->fi_fds[O_RDWR]); 637de18643dSTrond Myklebust return ret; 638de18643dSTrond Myklebust } 639de18643dSTrond Myklebust 640eb82dd39SJeff Layton static struct nfsd_file * 641de18643dSTrond Myklebust find_readable_file(struct nfs4_file *f) 642de18643dSTrond Myklebust { 643eb82dd39SJeff Layton struct nfsd_file *ret; 644de18643dSTrond Myklebust 645de18643dSTrond Myklebust spin_lock(&f->fi_lock); 646de18643dSTrond Myklebust ret = find_readable_file_locked(f); 647de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 648de18643dSTrond Myklebust 649de18643dSTrond Myklebust return ret; 650de18643dSTrond Myklebust } 651de18643dSTrond Myklebust 652eb82dd39SJeff Layton struct nfsd_file * 653de18643dSTrond Myklebust find_any_file(struct nfs4_file *f) 654de18643dSTrond Myklebust { 655eb82dd39SJeff Layton struct nfsd_file *ret; 656de18643dSTrond Myklebust 657a451b123STrond Myklebust if (!f) 658a451b123STrond Myklebust return NULL; 659de18643dSTrond Myklebust spin_lock(&f->fi_lock); 660edd2f552SJeff Layton ret = nfsd_file_get(f->fi_fds[O_RDWR]); 661de18643dSTrond Myklebust if (!ret) { 662edd2f552SJeff Layton ret = nfsd_file_get(f->fi_fds[O_WRONLY]); 663de18643dSTrond Myklebust if (!ret) 664edd2f552SJeff Layton ret = nfsd_file_get(f->fi_fds[O_RDONLY]); 665de18643dSTrond Myklebust } 666de18643dSTrond Myklebust spin_unlock(&f->fi_lock); 667de18643dSTrond Myklebust return ret; 668de18643dSTrond Myklebust } 669de18643dSTrond Myklebust 670e0aa6510SJeff Layton static struct nfsd_file *find_any_file_locked(struct nfs4_file *f) 6719affa435SJ. Bruce Fields { 672e0aa6510SJeff Layton lockdep_assert_held(&f->fi_lock); 6739affa435SJ. Bruce Fields 674e0aa6510SJeff Layton if (f->fi_fds[O_RDWR]) 675e0aa6510SJeff Layton return f->fi_fds[O_RDWR]; 676e0aa6510SJeff Layton if (f->fi_fds[O_WRONLY]) 677e0aa6510SJeff Layton return f->fi_fds[O_WRONLY]; 678e0aa6510SJeff Layton if (f->fi_fds[O_RDONLY]) 679e0aa6510SJeff Layton return f->fi_fds[O_RDONLY]; 680e0aa6510SJeff Layton return NULL; 681e0aa6510SJeff Layton } 682e0aa6510SJeff Layton 68302a3508dSTrond Myklebust static atomic_long_t num_delegations; 684697ce9beSZhang Yanfei unsigned long max_delegations; 685ef0f3390SNeilBrown 686ef0f3390SNeilBrown /* 687ef0f3390SNeilBrown * Open owner state (share locks) 688ef0f3390SNeilBrown */ 689ef0f3390SNeilBrown 69016bfdaafSJ. Bruce Fields /* hash tables for lock and open owners */ 69116bfdaafSJ. Bruce Fields #define OWNER_HASH_BITS 8 69216bfdaafSJ. Bruce Fields #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) 69316bfdaafSJ. Bruce Fields #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) 694ef0f3390SNeilBrown 695d4f0489fSTrond Myklebust static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) 696ddc04c41SJ. Bruce Fields { 697ddc04c41SJ. Bruce Fields unsigned int ret; 698ddc04c41SJ. Bruce Fields 699ddc04c41SJ. Bruce Fields ret = opaque_hashval(ownername->data, ownername->len); 70016bfdaafSJ. Bruce Fields return ret & OWNER_HASH_MASK; 701ddc04c41SJ. Bruce Fields } 702ef0f3390SNeilBrown 703d47b295eSChuck Lever static struct rhltable nfs4_file_rhltable ____cacheline_aligned_in_smp; 70435079582SShan Wei 705d47b295eSChuck Lever static const struct rhashtable_params nfs4_file_rhash_params = { 706d47b295eSChuck Lever .key_len = sizeof_field(struct nfs4_file, fi_inode), 707d47b295eSChuck Lever .key_offset = offsetof(struct nfs4_file, fi_inode), 708d47b295eSChuck Lever .head_offset = offsetof(struct nfs4_file, fi_rlist), 709ca943217STrond Myklebust 710d47b295eSChuck Lever /* 711d47b295eSChuck Lever * Start with a single page hash table to reduce resizing churn 712d47b295eSChuck Lever * on light workloads. 713d47b295eSChuck Lever */ 714d47b295eSChuck Lever .min_size = 256, 715d47b295eSChuck Lever .automatic_shrinking = true, 716d47b295eSChuck Lever }; 717ef0f3390SNeilBrown 7183d694271SDai Ngo /* 7193d694271SDai Ngo * Check if courtesy clients have conflicting access and resolve it if possible 7203d694271SDai Ngo * 7213d694271SDai Ngo * access: is op_share_access if share_access is true. 7223d694271SDai Ngo * Check if access mode, op_share_access, would conflict with 7233d694271SDai Ngo * the current deny mode of the file 'fp'. 7243d694271SDai Ngo * access: is op_share_deny if share_access is false. 7253d694271SDai Ngo * Check if the deny mode, op_share_deny, would conflict with 7263d694271SDai Ngo * current access of the file 'fp'. 7273d694271SDai Ngo * stp: skip checking this entry. 7283d694271SDai Ngo * new_stp: normal open, not open upgrade. 7293d694271SDai Ngo * 7303d694271SDai Ngo * Function returns: 7313d694271SDai Ngo * false - access/deny mode conflict with normal client. 7323d694271SDai Ngo * true - no conflict or conflict with courtesy client(s) is resolved. 7333d694271SDai Ngo */ 7343d694271SDai Ngo static bool 7353d694271SDai Ngo nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp, 7363d694271SDai Ngo struct nfs4_ol_stateid *stp, u32 access, bool share_access) 7373d694271SDai Ngo { 7383d694271SDai Ngo struct nfs4_ol_stateid *st; 7393d694271SDai Ngo bool resolvable = true; 7403d694271SDai Ngo unsigned char bmap; 7413d694271SDai Ngo struct nfsd_net *nn; 7423d694271SDai Ngo struct nfs4_client *clp; 7433d694271SDai Ngo 7443d694271SDai Ngo lockdep_assert_held(&fp->fi_lock); 7453d694271SDai Ngo list_for_each_entry(st, &fp->fi_stateids, st_perfile) { 7463d694271SDai Ngo /* ignore lock stateid */ 7473d694271SDai Ngo if (st->st_openstp) 7483d694271SDai Ngo continue; 7493d694271SDai Ngo if (st == stp && new_stp) 7503d694271SDai Ngo continue; 7513d694271SDai Ngo /* check file access against deny mode or vice versa */ 7523d694271SDai Ngo bmap = share_access ? st->st_deny_bmap : st->st_access_bmap; 7533d694271SDai Ngo if (!(access & bmap_to_share_mode(bmap))) 7543d694271SDai Ngo continue; 7553d694271SDai Ngo clp = st->st_stid.sc_client; 7563d694271SDai Ngo if (try_to_expire_client(clp)) 7573d694271SDai Ngo continue; 7583d694271SDai Ngo resolvable = false; 7593d694271SDai Ngo break; 7603d694271SDai Ngo } 7613d694271SDai Ngo if (resolvable) { 7623d694271SDai Ngo clp = stp->st_stid.sc_client; 7633d694271SDai Ngo nn = net_generic(clp->net, nfsd_net_id); 7643d694271SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 7653d694271SDai Ngo } 7663d694271SDai Ngo return resolvable; 7673d694271SDai Ngo } 7683d694271SDai Ngo 76912659651SJeff Layton static void 77012659651SJeff Layton __nfs4_file_get_access(struct nfs4_file *fp, u32 access) 7713477565eSJ. Bruce Fields { 7727214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 7737214e860SJeff Layton 77412659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 77512659651SJeff Layton atomic_inc(&fp->fi_access[O_WRONLY]); 77612659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 77712659651SJeff Layton atomic_inc(&fp->fi_access[O_RDONLY]); 7783477565eSJ. Bruce Fields } 7793477565eSJ. Bruce Fields 78012659651SJeff Layton static __be32 78112659651SJeff Layton nfs4_file_get_access(struct nfs4_file *fp, u32 access) 782998db52cSJ. Bruce Fields { 7837214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 7847214e860SJeff Layton 78512659651SJeff Layton /* Does this access mode make sense? */ 78612659651SJeff Layton if (access & ~NFS4_SHARE_ACCESS_BOTH) 78712659651SJeff Layton return nfserr_inval; 78812659651SJeff Layton 789baeb4ff0SJeff Layton /* Does it conflict with a deny mode already set? */ 790baeb4ff0SJeff Layton if ((access & fp->fi_share_deny) != 0) 791baeb4ff0SJeff Layton return nfserr_share_denied; 792baeb4ff0SJeff Layton 79312659651SJeff Layton __nfs4_file_get_access(fp, access); 79412659651SJeff Layton return nfs_ok; 795998db52cSJ. Bruce Fields } 796998db52cSJ. Bruce Fields 797baeb4ff0SJeff Layton static __be32 nfs4_file_check_deny(struct nfs4_file *fp, u32 deny) 798baeb4ff0SJeff Layton { 799baeb4ff0SJeff Layton /* Common case is that there is no deny mode. */ 800baeb4ff0SJeff Layton if (deny) { 801baeb4ff0SJeff Layton /* Does this deny mode make sense? */ 802baeb4ff0SJeff Layton if (deny & ~NFS4_SHARE_DENY_BOTH) 803baeb4ff0SJeff Layton return nfserr_inval; 804baeb4ff0SJeff Layton 805baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_READ) && 806baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_RDONLY])) 807baeb4ff0SJeff Layton return nfserr_share_denied; 808baeb4ff0SJeff Layton 809baeb4ff0SJeff Layton if ((deny & NFS4_SHARE_DENY_WRITE) && 810baeb4ff0SJeff Layton atomic_read(&fp->fi_access[O_WRONLY])) 811baeb4ff0SJeff Layton return nfserr_share_denied; 812baeb4ff0SJeff Layton } 813baeb4ff0SJeff Layton return nfs_ok; 814baeb4ff0SJeff Layton } 815baeb4ff0SJeff Layton 816998db52cSJ. Bruce Fields static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) 817f9d7562fSJ. Bruce Fields { 818de18643dSTrond Myklebust might_lock(&fp->fi_lock); 819de18643dSTrond Myklebust 820de18643dSTrond Myklebust if (atomic_dec_and_lock(&fp->fi_access[oflag], &fp->fi_lock)) { 821fd4f83fdSJeff Layton struct nfsd_file *f1 = NULL; 822fd4f83fdSJeff Layton struct nfsd_file *f2 = NULL; 823de18643dSTrond Myklebust 8246d338b51SJeff Layton swap(f1, fp->fi_fds[oflag]); 8250c7c3e67SJ. Bruce Fields if (atomic_read(&fp->fi_access[1 - oflag]) == 0) 8266d338b51SJeff Layton swap(f2, fp->fi_fds[O_RDWR]); 827de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 828de18643dSTrond Myklebust if (f1) 829dcf3f809SChuck Lever nfsd_file_put(f1); 830de18643dSTrond Myklebust if (f2) 831dcf3f809SChuck Lever nfsd_file_put(f2); 832f9d7562fSJ. Bruce Fields } 833f9d7562fSJ. Bruce Fields } 834f9d7562fSJ. Bruce Fields 83512659651SJeff Layton static void nfs4_file_put_access(struct nfs4_file *fp, u32 access) 836998db52cSJ. Bruce Fields { 83712659651SJeff Layton WARN_ON_ONCE(access & ~NFS4_SHARE_ACCESS_BOTH); 83812659651SJeff Layton 83912659651SJeff Layton if (access & NFS4_SHARE_ACCESS_WRITE) 840998db52cSJ. Bruce Fields __nfs4_file_put_access(fp, O_WRONLY); 84112659651SJeff Layton if (access & NFS4_SHARE_ACCESS_READ) 84212659651SJeff Layton __nfs4_file_put_access(fp, O_RDONLY); 843998db52cSJ. Bruce Fields } 844998db52cSJ. Bruce Fields 8458287f009SSachin Bhamare /* 8468287f009SSachin Bhamare * Allocate a new open/delegation state counter. This is needed for 8478287f009SSachin Bhamare * pNFS for proper return on close semantics. 8488287f009SSachin Bhamare * 8498287f009SSachin Bhamare * Note that we only allocate it for pNFS-enabled exports, otherwise 8508287f009SSachin Bhamare * all pointers to struct nfs4_clnt_odstate are always NULL. 8518287f009SSachin Bhamare */ 8528287f009SSachin Bhamare static struct nfs4_clnt_odstate * 8538287f009SSachin Bhamare alloc_clnt_odstate(struct nfs4_client *clp) 8548287f009SSachin Bhamare { 8558287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 8568287f009SSachin Bhamare 8578287f009SSachin Bhamare co = kmem_cache_zalloc(odstate_slab, GFP_KERNEL); 8588287f009SSachin Bhamare if (co) { 8598287f009SSachin Bhamare co->co_client = clp; 860cff7cb2eSElena Reshetova refcount_set(&co->co_odcount, 1); 8618287f009SSachin Bhamare } 8628287f009SSachin Bhamare return co; 8638287f009SSachin Bhamare } 8648287f009SSachin Bhamare 8658287f009SSachin Bhamare static void 8668287f009SSachin Bhamare hash_clnt_odstate_locked(struct nfs4_clnt_odstate *co) 8678287f009SSachin Bhamare { 8688287f009SSachin Bhamare struct nfs4_file *fp = co->co_file; 8698287f009SSachin Bhamare 8708287f009SSachin Bhamare lockdep_assert_held(&fp->fi_lock); 8718287f009SSachin Bhamare list_add(&co->co_perfile, &fp->fi_clnt_odstate); 8728287f009SSachin Bhamare } 8738287f009SSachin Bhamare 8748287f009SSachin Bhamare static inline void 8758287f009SSachin Bhamare get_clnt_odstate(struct nfs4_clnt_odstate *co) 8768287f009SSachin Bhamare { 8778287f009SSachin Bhamare if (co) 878cff7cb2eSElena Reshetova refcount_inc(&co->co_odcount); 8798287f009SSachin Bhamare } 8808287f009SSachin Bhamare 8818287f009SSachin Bhamare static void 8828287f009SSachin Bhamare put_clnt_odstate(struct nfs4_clnt_odstate *co) 8838287f009SSachin Bhamare { 8848287f009SSachin Bhamare struct nfs4_file *fp; 8858287f009SSachin Bhamare 8868287f009SSachin Bhamare if (!co) 8878287f009SSachin Bhamare return; 8888287f009SSachin Bhamare 8898287f009SSachin Bhamare fp = co->co_file; 890cff7cb2eSElena Reshetova if (refcount_dec_and_lock(&co->co_odcount, &fp->fi_lock)) { 8918287f009SSachin Bhamare list_del(&co->co_perfile); 8928287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 8938287f009SSachin Bhamare 8948287f009SSachin Bhamare nfsd4_return_all_file_layouts(co->co_client, fp); 8958287f009SSachin Bhamare kmem_cache_free(odstate_slab, co); 8968287f009SSachin Bhamare } 8978287f009SSachin Bhamare } 8988287f009SSachin Bhamare 8998287f009SSachin Bhamare static struct nfs4_clnt_odstate * 9008287f009SSachin Bhamare find_or_hash_clnt_odstate(struct nfs4_file *fp, struct nfs4_clnt_odstate *new) 9018287f009SSachin Bhamare { 9028287f009SSachin Bhamare struct nfs4_clnt_odstate *co; 9038287f009SSachin Bhamare struct nfs4_client *cl; 9048287f009SSachin Bhamare 9058287f009SSachin Bhamare if (!new) 9068287f009SSachin Bhamare return NULL; 9078287f009SSachin Bhamare 9088287f009SSachin Bhamare cl = new->co_client; 9098287f009SSachin Bhamare 9108287f009SSachin Bhamare spin_lock(&fp->fi_lock); 9118287f009SSachin Bhamare list_for_each_entry(co, &fp->fi_clnt_odstate, co_perfile) { 9128287f009SSachin Bhamare if (co->co_client == cl) { 9138287f009SSachin Bhamare get_clnt_odstate(co); 9148287f009SSachin Bhamare goto out; 9158287f009SSachin Bhamare } 9168287f009SSachin Bhamare } 9178287f009SSachin Bhamare co = new; 9188287f009SSachin Bhamare co->co_file = fp; 9198287f009SSachin Bhamare hash_clnt_odstate_locked(new); 9208287f009SSachin Bhamare out: 9218287f009SSachin Bhamare spin_unlock(&fp->fi_lock); 9228287f009SSachin Bhamare return co; 9238287f009SSachin Bhamare } 9248287f009SSachin Bhamare 925d19fb70dSKinglong Mee struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 926d19fb70dSKinglong Mee void (*sc_free)(struct nfs4_stid *)) 927996e0938SJ. Bruce Fields { 9283abdb607SJ. Bruce Fields struct nfs4_stid *stid; 9293abdb607SJ. Bruce Fields int new_id; 9303abdb607SJ. Bruce Fields 931f8338834STrond Myklebust stid = kmem_cache_zalloc(slab, GFP_KERNEL); 9323abdb607SJ. Bruce Fields if (!stid) 9333abdb607SJ. Bruce Fields return NULL; 934996e0938SJ. Bruce Fields 9354770d722SJeff Layton idr_preload(GFP_KERNEL); 9364770d722SJeff Layton spin_lock(&cl->cl_lock); 93778599c42SJ. Bruce Fields /* Reserving 0 for start of file in nfsdfs "states" file: */ 93878599c42SJ. Bruce Fields new_id = idr_alloc_cyclic(&cl->cl_stateids, stid, 1, 0, GFP_NOWAIT); 9394770d722SJeff Layton spin_unlock(&cl->cl_lock); 9404770d722SJeff Layton idr_preload_end(); 941ebd6c707STejun Heo if (new_id < 0) 9423abdb607SJ. Bruce Fields goto out_free; 943d19fb70dSKinglong Mee 944d19fb70dSKinglong Mee stid->sc_free = sc_free; 9453abdb607SJ. Bruce Fields stid->sc_client = cl; 9463abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_id = new_id; 9473abdb607SJ. Bruce Fields stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid; 9483abdb607SJ. Bruce Fields /* Will be incremented before return to client: */ 949a15dfcd5SElena Reshetova refcount_set(&stid->sc_count, 1); 9509767feb2SJeff Layton spin_lock_init(&stid->sc_lock); 951624322f1SOlga Kornievskaia INIT_LIST_HEAD(&stid->sc_cp_list); 9523abdb607SJ. Bruce Fields 953996e0938SJ. Bruce Fields /* 9543abdb607SJ. Bruce Fields * It shouldn't be a problem to reuse an opaque stateid value. 9553abdb607SJ. Bruce Fields * I don't think it is for 4.1. But with 4.0 I worry that, for 9563abdb607SJ. Bruce Fields * example, a stray write retransmission could be accepted by 9573abdb607SJ. Bruce Fields * the server when it should have been rejected. Therefore, 9583abdb607SJ. Bruce Fields * adopt a trick from the sctp code to attempt to maximize the 9593abdb607SJ. Bruce Fields * amount of time until an id is reused, by ensuring they always 9603abdb607SJ. Bruce Fields * "increase" (mod INT_MAX): 961996e0938SJ. Bruce Fields */ 9623abdb607SJ. Bruce Fields return stid; 9633abdb607SJ. Bruce Fields out_free: 9642c44a234SWei Yongjun kmem_cache_free(slab, stid); 9653abdb607SJ. Bruce Fields return NULL; 9662a74aba7SJ. Bruce Fields } 9672a74aba7SJ. Bruce Fields 968e0639dc5SOlga Kornievskaia /* 969e0639dc5SOlga Kornievskaia * Create a unique stateid_t to represent each COPY. 970e0639dc5SOlga Kornievskaia */ 971624322f1SOlga Kornievskaia static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, 972781fde1aSChuck Lever unsigned char cs_type) 973e0639dc5SOlga Kornievskaia { 974e0639dc5SOlga Kornievskaia int new_id; 975e0639dc5SOlga Kornievskaia 976781fde1aSChuck Lever stid->cs_stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; 977781fde1aSChuck Lever stid->cs_stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; 978624322f1SOlga Kornievskaia 979e0639dc5SOlga Kornievskaia idr_preload(GFP_KERNEL); 980e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 981624322f1SOlga Kornievskaia new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT); 982781fde1aSChuck Lever stid->cs_stid.si_opaque.so_id = new_id; 983781fde1aSChuck Lever stid->cs_stid.si_generation = 1; 984e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 985e0639dc5SOlga Kornievskaia idr_preload_end(); 986e0639dc5SOlga Kornievskaia if (new_id < 0) 987e0639dc5SOlga Kornievskaia return 0; 98881e72297SDai Ngo stid->cs_type = cs_type; 989e0639dc5SOlga Kornievskaia return 1; 990e0639dc5SOlga Kornievskaia } 991e0639dc5SOlga Kornievskaia 992624322f1SOlga Kornievskaia int nfs4_init_copy_state(struct nfsd_net *nn, struct nfsd4_copy *copy) 993624322f1SOlga Kornievskaia { 994624322f1SOlga Kornievskaia return nfs4_init_cp_state(nn, ©->cp_stateid, NFS4_COPY_STID); 995624322f1SOlga Kornievskaia } 996624322f1SOlga Kornievskaia 997624322f1SOlga Kornievskaia struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, 998624322f1SOlga Kornievskaia struct nfs4_stid *p_stid) 999624322f1SOlga Kornievskaia { 1000624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 1001624322f1SOlga Kornievskaia 1002624322f1SOlga Kornievskaia cps = kzalloc(sizeof(struct nfs4_cpntf_state), GFP_KERNEL); 1003624322f1SOlga Kornievskaia if (!cps) 1004624322f1SOlga Kornievskaia return NULL; 100520b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 1006781fde1aSChuck Lever refcount_set(&cps->cp_stateid.cs_count, 1); 1007624322f1SOlga Kornievskaia if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID)) 1008624322f1SOlga Kornievskaia goto out_free; 1009624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1010624322f1SOlga Kornievskaia list_add(&cps->cp_list, &p_stid->sc_cp_list); 1011624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1012624322f1SOlga Kornievskaia return cps; 1013624322f1SOlga Kornievskaia out_free: 1014624322f1SOlga Kornievskaia kfree(cps); 1015624322f1SOlga Kornievskaia return NULL; 1016624322f1SOlga Kornievskaia } 1017624322f1SOlga Kornievskaia 1018624322f1SOlga Kornievskaia void nfs4_free_copy_state(struct nfsd4_copy *copy) 1019e0639dc5SOlga Kornievskaia { 1020e0639dc5SOlga Kornievskaia struct nfsd_net *nn; 1021e0639dc5SOlga Kornievskaia 102281e72297SDai Ngo if (copy->cp_stateid.cs_type != NFS4_COPY_STID) 102381e72297SDai Ngo return; 1024e0639dc5SOlga Kornievskaia nn = net_generic(copy->cp_clp->net, nfsd_net_id); 1025e0639dc5SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1026624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 1027781fde1aSChuck Lever copy->cp_stateid.cs_stid.si_opaque.so_id); 1028624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1029624322f1SOlga Kornievskaia } 1030624322f1SOlga Kornievskaia 1031624322f1SOlga Kornievskaia static void nfs4_free_cpntf_statelist(struct net *net, struct nfs4_stid *stid) 1032624322f1SOlga Kornievskaia { 1033624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 1034624322f1SOlga Kornievskaia struct nfsd_net *nn; 1035624322f1SOlga Kornievskaia 1036624322f1SOlga Kornievskaia nn = net_generic(net, nfsd_net_id); 1037624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 1038624322f1SOlga Kornievskaia while (!list_empty(&stid->sc_cp_list)) { 1039624322f1SOlga Kornievskaia cps = list_first_entry(&stid->sc_cp_list, 1040624322f1SOlga Kornievskaia struct nfs4_cpntf_state, cp_list); 1041624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 1042624322f1SOlga Kornievskaia } 1043e0639dc5SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 1044e0639dc5SOlga Kornievskaia } 1045e0639dc5SOlga Kornievskaia 1046b49e084dSJeff Layton static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 10474cdc951bSJ. Bruce Fields { 10486011695dSTrond Myklebust struct nfs4_stid *stid; 10496011695dSTrond Myklebust 1050d19fb70dSKinglong Mee stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid); 10516011695dSTrond Myklebust if (!stid) 10526011695dSTrond Myklebust return NULL; 10536011695dSTrond Myklebust 1054d19fb70dSKinglong Mee return openlockstateid(stid); 10556011695dSTrond Myklebust } 10566011695dSTrond Myklebust 10576011695dSTrond Myklebust static void nfs4_free_deleg(struct nfs4_stid *stid) 10586011695dSTrond Myklebust { 1059895ddf5eSJeff Layton struct nfs4_delegation *dp = delegstateid(stid); 1060895ddf5eSJeff Layton 1061895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&stid->sc_cp_list)); 1062895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&dp->dl_perfile)); 1063895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&dp->dl_perclnt)); 1064895ddf5eSJeff Layton WARN_ON_ONCE(!list_empty(&dp->dl_recall_lru)); 10656011695dSTrond Myklebust kmem_cache_free(deleg_slab, stid); 10666011695dSTrond Myklebust atomic_long_dec(&num_delegations); 10674cdc951bSJ. Bruce Fields } 10684cdc951bSJ. Bruce Fields 10696282cd56SNeilBrown /* 10706282cd56SNeilBrown * When we recall a delegation, we should be careful not to hand it 10716282cd56SNeilBrown * out again straight away. 10726282cd56SNeilBrown * To ensure this we keep a pair of bloom filters ('new' and 'old') 10736282cd56SNeilBrown * in which the filehandles of recalled delegations are "stored". 10746282cd56SNeilBrown * If a filehandle appear in either filter, a delegation is blocked. 10756282cd56SNeilBrown * When a delegation is recalled, the filehandle is stored in the "new" 10766282cd56SNeilBrown * filter. 10776282cd56SNeilBrown * Every 30 seconds we swap the filters and clear the "new" one, 10786282cd56SNeilBrown * unless both are empty of course. 10796282cd56SNeilBrown * 10806282cd56SNeilBrown * Each filter is 256 bits. We hash the filehandle to 32bit and use the 10816282cd56SNeilBrown * low 3 bytes as hash-table indices. 10826282cd56SNeilBrown * 1083f54fe962SJeff Layton * 'blocked_delegations_lock', which is always taken in block_delegations(), 10846282cd56SNeilBrown * is used to manage concurrent access. Testing does not need the lock 10856282cd56SNeilBrown * except when swapping the two filters. 10866282cd56SNeilBrown */ 1087f54fe962SJeff Layton static DEFINE_SPINLOCK(blocked_delegations_lock); 10886282cd56SNeilBrown static struct bloom_pair { 10896282cd56SNeilBrown int entries, old_entries; 1090b3f255efSArnd Bergmann time64_t swap_time; 10916282cd56SNeilBrown int new; /* index into 'set' */ 10926282cd56SNeilBrown DECLARE_BITMAP(set[2], 256); 10936282cd56SNeilBrown } blocked_delegations; 10946282cd56SNeilBrown 10956282cd56SNeilBrown static int delegation_blocked(struct knfsd_fh *fh) 10966282cd56SNeilBrown { 10976282cd56SNeilBrown u32 hash; 10986282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 10996282cd56SNeilBrown 11006282cd56SNeilBrown if (bd->entries == 0) 11016282cd56SNeilBrown return 0; 1102b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 1103f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 1104b3f255efSArnd Bergmann if (ktime_get_seconds() - bd->swap_time > 30) { 11056282cd56SNeilBrown bd->entries -= bd->old_entries; 11066282cd56SNeilBrown bd->old_entries = bd->entries; 11076282cd56SNeilBrown memset(bd->set[bd->new], 0, 11086282cd56SNeilBrown sizeof(bd->set[0])); 11096282cd56SNeilBrown bd->new = 1-bd->new; 1110b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 11116282cd56SNeilBrown } 1112f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 11136282cd56SNeilBrown } 1114d8b26071SNeilBrown hash = jhash(&fh->fh_raw, fh->fh_size, 0); 11156282cd56SNeilBrown if (test_bit(hash&255, bd->set[0]) && 11166282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[0]) && 11176282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[0])) 11186282cd56SNeilBrown return 1; 11196282cd56SNeilBrown 11206282cd56SNeilBrown if (test_bit(hash&255, bd->set[1]) && 11216282cd56SNeilBrown test_bit((hash>>8)&255, bd->set[1]) && 11226282cd56SNeilBrown test_bit((hash>>16)&255, bd->set[1])) 11236282cd56SNeilBrown return 1; 11246282cd56SNeilBrown 11256282cd56SNeilBrown return 0; 11266282cd56SNeilBrown } 11276282cd56SNeilBrown 11286282cd56SNeilBrown static void block_delegations(struct knfsd_fh *fh) 11296282cd56SNeilBrown { 11306282cd56SNeilBrown u32 hash; 11316282cd56SNeilBrown struct bloom_pair *bd = &blocked_delegations; 11326282cd56SNeilBrown 1133d8b26071SNeilBrown hash = jhash(&fh->fh_raw, fh->fh_size, 0); 11346282cd56SNeilBrown 1135f54fe962SJeff Layton spin_lock(&blocked_delegations_lock); 11366282cd56SNeilBrown __set_bit(hash&255, bd->set[bd->new]); 11376282cd56SNeilBrown __set_bit((hash>>8)&255, bd->set[bd->new]); 11386282cd56SNeilBrown __set_bit((hash>>16)&255, bd->set[bd->new]); 11396282cd56SNeilBrown if (bd->entries == 0) 1140b3f255efSArnd Bergmann bd->swap_time = ktime_get_seconds(); 11416282cd56SNeilBrown bd->entries += 1; 1142f54fe962SJeff Layton spin_unlock(&blocked_delegations_lock); 11436282cd56SNeilBrown } 11446282cd56SNeilBrown 11451da177e4SLinus Torvalds static struct nfs4_delegation * 114686d29b10SJ. Bruce Fields alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, 11478287f009SSachin Bhamare struct nfs4_clnt_odstate *odstate) 11481da177e4SLinus Torvalds { 11491da177e4SLinus Torvalds struct nfs4_delegation *dp; 115002a3508dSTrond Myklebust long n; 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds dprintk("NFSD alloc_init_deleg\n"); 115302a3508dSTrond Myklebust n = atomic_long_inc_return(&num_delegations); 115402a3508dSTrond Myklebust if (n < 0 || n > max_delegations) 115502a3508dSTrond Myklebust goto out_dec; 1156bbf936edSJeff Layton if (delegation_blocked(&fp->fi_fhandle)) 115702a3508dSTrond Myklebust goto out_dec; 1158d19fb70dSKinglong Mee dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); 11595b2d21c1SNeilBrown if (dp == NULL) 116002a3508dSTrond Myklebust goto out_dec; 11616011695dSTrond Myklebust 11622a74aba7SJ. Bruce Fields /* 11632a74aba7SJ. Bruce Fields * delegation seqid's are never incremented. The 4.1 special 11646136d2b4SJ. Bruce Fields * meaning of seqid 0 isn't meaningful, really, but let's avoid 11656136d2b4SJ. Bruce Fields * 0 anyway just for consistency and use 1: 11662a74aba7SJ. Bruce Fields */ 11672a74aba7SJ. Bruce Fields dp->dl_stid.sc_stateid.si_generation = 1; 1168ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perfile); 1169ea1da636SNeilBrown INIT_LIST_HEAD(&dp->dl_perclnt); 11701da177e4SLinus Torvalds INIT_LIST_HEAD(&dp->dl_recall_lru); 11718287f009SSachin Bhamare dp->dl_clnt_odstate = odstate; 11728287f009SSachin Bhamare get_clnt_odstate(odstate); 117399c41515SJ. Bruce Fields dp->dl_type = NFS4_OPEN_DELEGATE_READ; 1174f0b5de1bSChristoph Hellwig dp->dl_retries = 1; 117566af2579SDai Ngo dp->dl_recalled = false; 1176f0b5de1bSChristoph Hellwig nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, 11770162ac2bSChristoph Hellwig &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); 117886d29b10SJ. Bruce Fields get_nfs4_file(fp); 117986d29b10SJ. Bruce Fields dp->dl_stid.sc_file = fp; 11801da177e4SLinus Torvalds return dp; 118102a3508dSTrond Myklebust out_dec: 118202a3508dSTrond Myklebust atomic_long_dec(&num_delegations); 118302a3508dSTrond Myklebust return NULL; 11841da177e4SLinus Torvalds } 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds void 11876011695dSTrond Myklebust nfs4_put_stid(struct nfs4_stid *s) 11881da177e4SLinus Torvalds { 118911b9164aSTrond Myklebust struct nfs4_file *fp = s->sc_file; 11906011695dSTrond Myklebust struct nfs4_client *clp = s->sc_client; 11916011695dSTrond Myklebust 11924770d722SJeff Layton might_lock(&clp->cl_lock); 11934770d722SJeff Layton 1194a15dfcd5SElena Reshetova if (!refcount_dec_and_lock(&s->sc_count, &clp->cl_lock)) { 1195b401be22SJeff Layton wake_up_all(&close_wq); 11966011695dSTrond Myklebust return; 1197b401be22SJeff Layton } 11986011695dSTrond Myklebust idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 1199624322f1SOlga Kornievskaia nfs4_free_cpntf_statelist(clp->net, s); 12004770d722SJeff Layton spin_unlock(&clp->cl_lock); 12016011695dSTrond Myklebust s->sc_free(s); 120211b9164aSTrond Myklebust if (fp) 120311b9164aSTrond Myklebust put_nfs4_file(fp); 12041da177e4SLinus Torvalds } 12051da177e4SLinus Torvalds 12069767feb2SJeff Layton void 12079767feb2SJeff Layton nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid) 12089767feb2SJeff Layton { 12099767feb2SJeff Layton stateid_t *src = &stid->sc_stateid; 12109767feb2SJeff Layton 12119767feb2SJeff Layton spin_lock(&stid->sc_lock); 12129767feb2SJeff Layton if (unlikely(++src->si_generation == 0)) 12139767feb2SJeff Layton src->si_generation = 1; 12149767feb2SJeff Layton memcpy(dst, src, sizeof(*dst)); 12159767feb2SJeff Layton spin_unlock(&stid->sc_lock); 12169767feb2SJeff Layton } 12179767feb2SJeff Layton 1218353601e7SJ. Bruce Fields static void put_deleg_file(struct nfs4_file *fp) 12191da177e4SLinus Torvalds { 1220eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 1221353601e7SJ. Bruce Fields 1222353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 1223353601e7SJ. Bruce Fields if (--fp->fi_delegees == 0) 1224eb82dd39SJeff Layton swap(nf, fp->fi_deleg_file); 1225353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 1226353601e7SJ. Bruce Fields 1227eb82dd39SJeff Layton if (nf) 1228eb82dd39SJeff Layton nfsd_file_put(nf); 1229353601e7SJ. Bruce Fields } 1230353601e7SJ. Bruce Fields 1231353601e7SJ. Bruce Fields static void nfs4_unlock_deleg_lease(struct nfs4_delegation *dp) 1232353601e7SJ. Bruce Fields { 1233cba7b3d1SJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 1234eb82dd39SJeff Layton struct nfsd_file *nf = fp->fi_deleg_file; 1235417c6629SJeff Layton 1236b8232d33SJ. Bruce Fields WARN_ON_ONCE(!fp->fi_delegees); 1237b8232d33SJ. Bruce Fields 1238eb82dd39SJeff Layton vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp); 1239353601e7SJ. Bruce Fields put_deleg_file(fp); 12401da177e4SLinus Torvalds } 12411da177e4SLinus Torvalds 12420af6e690SJ. Bruce Fields static void destroy_unhashed_deleg(struct nfs4_delegation *dp) 12430af6e690SJ. Bruce Fields { 12440af6e690SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 1245353601e7SJ. Bruce Fields nfs4_unlock_deleg_lease(dp); 12460af6e690SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 12470af6e690SJ. Bruce Fields } 12480af6e690SJ. Bruce Fields 1249cd61c522SChristoph Hellwig void nfs4_unhash_stid(struct nfs4_stid *s) 12506136d2b4SJ. Bruce Fields { 12513abdb607SJ. Bruce Fields s->sc_type = 0; 12526136d2b4SJ. Bruce Fields } 12536136d2b4SJ. Bruce Fields 125434ed9872SAndrew Elble /** 125568b18f52SJ. Bruce Fields * nfs4_delegation_exists - Discover if this delegation already exists 125634ed9872SAndrew Elble * @clp: a pointer to the nfs4_client we're granting a delegation to 125734ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 125834ed9872SAndrew Elble * 125934ed9872SAndrew Elble * Return: 126068b18f52SJ. Bruce Fields * On success: true iff an existing delegation is found 126134ed9872SAndrew Elble */ 126234ed9872SAndrew Elble 126368b18f52SJ. Bruce Fields static bool 126468b18f52SJ. Bruce Fields nfs4_delegation_exists(struct nfs4_client *clp, struct nfs4_file *fp) 1265931ee56cSBenny Halevy { 126634ed9872SAndrew Elble struct nfs4_delegation *searchdp = NULL; 126734ed9872SAndrew Elble struct nfs4_client *searchclp = NULL; 126834ed9872SAndrew Elble 1269cdc97505SBenny Halevy lockdep_assert_held(&state_lock); 1270417c6629SJeff Layton lockdep_assert_held(&fp->fi_lock); 1271931ee56cSBenny Halevy 127234ed9872SAndrew Elble list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { 127334ed9872SAndrew Elble searchclp = searchdp->dl_stid.sc_client; 127434ed9872SAndrew Elble if (clp == searchclp) { 127551d87bc2SFengguang Wu return true; 127634ed9872SAndrew Elble } 127734ed9872SAndrew Elble } 127851d87bc2SFengguang Wu return false; 127934ed9872SAndrew Elble } 128034ed9872SAndrew Elble 128134ed9872SAndrew Elble /** 128234ed9872SAndrew Elble * hash_delegation_locked - Add a delegation to the appropriate lists 128334ed9872SAndrew Elble * @dp: a pointer to the nfs4_delegation we are adding. 128434ed9872SAndrew Elble * @fp: a pointer to the nfs4_file we're granting a delegation on 128534ed9872SAndrew Elble * 128634ed9872SAndrew Elble * Return: 128734ed9872SAndrew Elble * On success: NULL if the delegation was successfully hashed. 128834ed9872SAndrew Elble * 128934ed9872SAndrew Elble * On error: -EAGAIN if one was previously granted to this 129034ed9872SAndrew Elble * nfs4_client for this nfs4_file. Delegation is not hashed. 129134ed9872SAndrew Elble * 129234ed9872SAndrew Elble */ 129334ed9872SAndrew Elble 129434ed9872SAndrew Elble static int 129534ed9872SAndrew Elble hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 129634ed9872SAndrew Elble { 129734ed9872SAndrew Elble struct nfs4_client *clp = dp->dl_stid.sc_client; 129834ed9872SAndrew Elble 129934ed9872SAndrew Elble lockdep_assert_held(&state_lock); 130034ed9872SAndrew Elble lockdep_assert_held(&fp->fi_lock); 130134ed9872SAndrew Elble 130268b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 130368b18f52SJ. Bruce Fields return -EAGAIN; 1304a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 13053fb87d13SBenny Halevy dp->dl_stid.sc_type = NFS4_DELEG_STID; 1306931ee56cSBenny Halevy list_add(&dp->dl_perfile, &fp->fi_delegations); 130734ed9872SAndrew Elble list_add(&dp->dl_perclnt, &clp->cl_delegations); 130834ed9872SAndrew Elble return 0; 1309931ee56cSBenny Halevy } 1310931ee56cSBenny Halevy 1311548ec080SJ. Bruce Fields static bool delegation_hashed(struct nfs4_delegation *dp) 1312548ec080SJ. Bruce Fields { 1313548ec080SJ. Bruce Fields return !(list_empty(&dp->dl_perfile)); 1314548ec080SJ. Bruce Fields } 1315548ec080SJ. Bruce Fields 13163fcbbd24SJeff Layton static bool 131742690676SJeff Layton unhash_delegation_locked(struct nfs4_delegation *dp) 13181da177e4SLinus Torvalds { 131911b9164aSTrond Myklebust struct nfs4_file *fp = dp->dl_stid.sc_file; 132002e1215fSJeff Layton 132142690676SJeff Layton lockdep_assert_held(&state_lock); 132242690676SJeff Layton 1323548ec080SJ. Bruce Fields if (!delegation_hashed(dp)) 13243fcbbd24SJeff Layton return false; 13253fcbbd24SJeff Layton 1326b0fc29d6STrond Myklebust dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; 1327d55a166cSJeff Layton /* Ensure that deleg break won't try to requeue it */ 1328d55a166cSJeff Layton ++dp->dl_time; 1329417c6629SJeff Layton spin_lock(&fp->fi_lock); 1330931ee56cSBenny Halevy list_del_init(&dp->dl_perclnt); 13311da177e4SLinus Torvalds list_del_init(&dp->dl_recall_lru); 133202e1215fSJeff Layton list_del_init(&dp->dl_perfile); 133302e1215fSJeff Layton spin_unlock(&fp->fi_lock); 13343fcbbd24SJeff Layton return true; 1335cbf7a75bSJ. Bruce Fields } 13363bd64a5bSJ. Bruce Fields 13373bd64a5bSJ. Bruce Fields static void destroy_delegation(struct nfs4_delegation *dp) 13383bd64a5bSJ. Bruce Fields { 13393fcbbd24SJeff Layton bool unhashed; 13403fcbbd24SJeff Layton 134142690676SJeff Layton spin_lock(&state_lock); 13423fcbbd24SJeff Layton unhashed = unhash_delegation_locked(dp); 134342690676SJeff Layton spin_unlock(&state_lock); 13440af6e690SJ. Bruce Fields if (unhashed) 13450af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 13463fcbbd24SJeff Layton } 13473bd64a5bSJ. Bruce Fields 13483bd64a5bSJ. Bruce Fields static void revoke_delegation(struct nfs4_delegation *dp) 13493bd64a5bSJ. Bruce Fields { 13503bd64a5bSJ. Bruce Fields struct nfs4_client *clp = dp->dl_stid.sc_client; 13513bd64a5bSJ. Bruce Fields 13522d4a532dSJeff Layton WARN_ON(!list_empty(&dp->dl_recall_lru)); 13532d4a532dSJeff Layton 1354a1c74569SChuck Lever trace_nfsd_stid_revoke(&dp->dl_stid); 1355a1c74569SChuck Lever 13560af6e690SJ. Bruce Fields if (clp->cl_minorversion) { 13573b816601SBenjamin Coddington spin_lock(&clp->cl_lock); 13583bd64a5bSJ. Bruce Fields dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; 13590af6e690SJ. Bruce Fields refcount_inc(&dp->dl_stid.sc_count); 13602d4a532dSJeff Layton list_add(&dp->dl_recall_lru, &clp->cl_revoked); 13612d4a532dSJeff Layton spin_unlock(&clp->cl_lock); 13623bd64a5bSJ. Bruce Fields } 13630af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 13643bd64a5bSJ. Bruce Fields } 13653bd64a5bSJ. Bruce Fields 13661da177e4SLinus Torvalds /* 13671da177e4SLinus Torvalds * SETCLIENTID state 13681da177e4SLinus Torvalds */ 13691da177e4SLinus Torvalds 1370ddc04c41SJ. Bruce Fields static unsigned int clientid_hashval(u32 id) 1371ddc04c41SJ. Bruce Fields { 1372ddc04c41SJ. Bruce Fields return id & CLIENT_HASH_MASK; 1373ddc04c41SJ. Bruce Fields } 1374ddc04c41SJ. Bruce Fields 13756b189105SScott Mayhew static unsigned int clientstr_hashval(struct xdr_netobj name) 1376ddc04c41SJ. Bruce Fields { 13776b189105SScott Mayhew return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; 1378ddc04c41SJ. Bruce Fields } 1379ddc04c41SJ. Bruce Fields 13801da177e4SLinus Torvalds /* 1381baeb4ff0SJeff Layton * A stateid that had a deny mode associated with it is being released 1382baeb4ff0SJeff Layton * or downgraded. Recalculate the deny mode on the file. 1383baeb4ff0SJeff Layton */ 1384baeb4ff0SJeff Layton static void 1385baeb4ff0SJeff Layton recalculate_deny_mode(struct nfs4_file *fp) 1386baeb4ff0SJeff Layton { 1387baeb4ff0SJeff Layton struct nfs4_ol_stateid *stp; 1388baeb4ff0SJeff Layton 1389baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 1390baeb4ff0SJeff Layton fp->fi_share_deny = 0; 1391baeb4ff0SJeff Layton list_for_each_entry(stp, &fp->fi_stateids, st_perfile) 1392baeb4ff0SJeff Layton fp->fi_share_deny |= bmap_to_share_mode(stp->st_deny_bmap); 1393baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 1394baeb4ff0SJeff Layton } 1395baeb4ff0SJeff Layton 1396baeb4ff0SJeff Layton static void 1397baeb4ff0SJeff Layton reset_union_bmap_deny(u32 deny, struct nfs4_ol_stateid *stp) 1398baeb4ff0SJeff Layton { 1399baeb4ff0SJeff Layton int i; 1400baeb4ff0SJeff Layton bool change = false; 1401baeb4ff0SJeff Layton 1402baeb4ff0SJeff Layton for (i = 1; i < 4; i++) { 1403baeb4ff0SJeff Layton if ((i & deny) != i) { 1404baeb4ff0SJeff Layton change = true; 1405baeb4ff0SJeff Layton clear_deny(i, stp); 1406baeb4ff0SJeff Layton } 1407baeb4ff0SJeff Layton } 1408baeb4ff0SJeff Layton 1409baeb4ff0SJeff Layton /* Recalculate per-file deny mode if there was a change */ 1410baeb4ff0SJeff Layton if (change) 141111b9164aSTrond Myklebust recalculate_deny_mode(stp->st_stid.sc_file); 1412baeb4ff0SJeff Layton } 1413baeb4ff0SJeff Layton 141482c5ff1bSJeff Layton /* release all access and file references for a given stateid */ 141582c5ff1bSJeff Layton static void 141682c5ff1bSJeff Layton release_all_access(struct nfs4_ol_stateid *stp) 141782c5ff1bSJeff Layton { 141882c5ff1bSJeff Layton int i; 141911b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 1420baeb4ff0SJeff Layton 1421baeb4ff0SJeff Layton if (fp && stp->st_deny_bmap != 0) 1422baeb4ff0SJeff Layton recalculate_deny_mode(fp); 142382c5ff1bSJeff Layton 142482c5ff1bSJeff Layton for (i = 1; i < 4; i++) { 142582c5ff1bSJeff Layton if (test_access(i, stp)) 142611b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, i); 142782c5ff1bSJeff Layton clear_access(i, stp); 142882c5ff1bSJeff Layton } 142982c5ff1bSJeff Layton } 143082c5ff1bSJeff Layton 1431d50ffdedSKinglong Mee static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1432d50ffdedSKinglong Mee { 1433d50ffdedSKinglong Mee kfree(sop->so_owner.data); 1434d50ffdedSKinglong Mee sop->so_ops->so_free(sop); 1435d50ffdedSKinglong Mee } 1436d50ffdedSKinglong Mee 14376b180f0bSJeff Layton static void nfs4_put_stateowner(struct nfs4_stateowner *sop) 14386b180f0bSJeff Layton { 1439a819ecc1SJeff Layton struct nfs4_client *clp = sop->so_client; 1440a819ecc1SJeff Layton 1441a819ecc1SJeff Layton might_lock(&clp->cl_lock); 1442a819ecc1SJeff Layton 1443a819ecc1SJeff Layton if (!atomic_dec_and_lock(&sop->so_count, &clp->cl_lock)) 14446b180f0bSJeff Layton return; 14458f4b54c5SJeff Layton sop->so_ops->so_unhash(sop); 1446a819ecc1SJeff Layton spin_unlock(&clp->cl_lock); 1447d50ffdedSKinglong Mee nfs4_free_stateowner(sop); 14486b180f0bSJeff Layton } 14496b180f0bSJeff Layton 1450a451b123STrond Myklebust static bool 1451a451b123STrond Myklebust nfs4_ol_stateid_unhashed(const struct nfs4_ol_stateid *stp) 1452a451b123STrond Myklebust { 1453a451b123STrond Myklebust return list_empty(&stp->st_perfile); 1454a451b123STrond Myklebust } 1455a451b123STrond Myklebust 1456e8568739SJeff Layton static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) 1457529d7b2aSJ. Bruce Fields { 145811b9164aSTrond Myklebust struct nfs4_file *fp = stp->st_stid.sc_file; 14591d31a253STrond Myklebust 14601c755dc1SJeff Layton lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); 14611c755dc1SJeff Layton 1462e8568739SJeff Layton if (list_empty(&stp->st_perfile)) 1463e8568739SJeff Layton return false; 1464e8568739SJeff Layton 14651d31a253STrond Myklebust spin_lock(&fp->fi_lock); 1466e8568739SJeff Layton list_del_init(&stp->st_perfile); 14671d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 1468529d7b2aSJ. Bruce Fields list_del(&stp->st_perstateowner); 1469e8568739SJeff Layton return true; 1470529d7b2aSJ. Bruce Fields } 1471529d7b2aSJ. Bruce Fields 14726011695dSTrond Myklebust static void nfs4_free_ol_stateid(struct nfs4_stid *stid) 1473529d7b2aSJ. Bruce Fields { 14746011695dSTrond Myklebust struct nfs4_ol_stateid *stp = openlockstateid(stid); 14754665e2baSJ. Bruce Fields 14768287f009SSachin Bhamare put_clnt_odstate(stp->st_clnt_odstate); 14776011695dSTrond Myklebust release_all_access(stp); 1478d3134b10SJeff Layton if (stp->st_stateowner) 1479d3134b10SJeff Layton nfs4_put_stateowner(stp->st_stateowner); 1480019805feSDai Ngo WARN_ON(!list_empty(&stid->sc_cp_list)); 14816011695dSTrond Myklebust kmem_cache_free(stateid_slab, stid); 1482529d7b2aSJ. Bruce Fields } 1483529d7b2aSJ. Bruce Fields 1484b49e084dSJeff Layton static void nfs4_free_lock_stateid(struct nfs4_stid *stid) 1485529d7b2aSJ. Bruce Fields { 1486b49e084dSJeff Layton struct nfs4_ol_stateid *stp = openlockstateid(stid); 1487b49e084dSJeff Layton struct nfs4_lockowner *lo = lockowner(stp->st_stateowner); 1488eb82dd39SJeff Layton struct nfsd_file *nf; 1489529d7b2aSJ. Bruce Fields 1490eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 1491eb82dd39SJeff Layton if (nf) { 1492eb82dd39SJeff Layton get_file(nf->nf_file); 1493eb82dd39SJeff Layton filp_close(nf->nf_file, (fl_owner_t)lo); 1494eb82dd39SJeff Layton nfsd_file_put(nf); 1495eb82dd39SJeff Layton } 1496b49e084dSJeff Layton nfs4_free_ol_stateid(stid); 1497b49e084dSJeff Layton } 1498b49e084dSJeff Layton 14992c41beb0SJeff Layton /* 15002c41beb0SJeff Layton * Put the persistent reference to an already unhashed generic stateid, while 15012c41beb0SJeff Layton * holding the cl_lock. If it's the last reference, then put it onto the 15022c41beb0SJeff Layton * reaplist for later destruction. 15032c41beb0SJeff Layton */ 15042c41beb0SJeff Layton static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, 15052c41beb0SJeff Layton struct list_head *reaplist) 15062c41beb0SJeff Layton { 15072c41beb0SJeff Layton struct nfs4_stid *s = &stp->st_stid; 15082c41beb0SJeff Layton struct nfs4_client *clp = s->sc_client; 15092c41beb0SJeff Layton 15102c41beb0SJeff Layton lockdep_assert_held(&clp->cl_lock); 15112c41beb0SJeff Layton 15122c41beb0SJeff Layton WARN_ON_ONCE(!list_empty(&stp->st_locks)); 15132c41beb0SJeff Layton 1514a15dfcd5SElena Reshetova if (!refcount_dec_and_test(&s->sc_count)) { 15152c41beb0SJeff Layton wake_up_all(&close_wq); 15162c41beb0SJeff Layton return; 15172c41beb0SJeff Layton } 15182c41beb0SJeff Layton 15192c41beb0SJeff Layton idr_remove(&clp->cl_stateids, s->sc_stateid.si_opaque.so_id); 15202c41beb0SJeff Layton list_add(&stp->st_locks, reaplist); 15212c41beb0SJeff Layton } 15222c41beb0SJeff Layton 1523e8568739SJeff Layton static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) 15243c1c995cSJeff Layton { 1525f46c445bSChuck Lever lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 15263c1c995cSJeff Layton 1527a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1528a451b123STrond Myklebust return false; 15293c1c995cSJeff Layton list_del_init(&stp->st_locks); 1530cd61c522SChristoph Hellwig nfs4_unhash_stid(&stp->st_stid); 1531a451b123STrond Myklebust return true; 15323c1c995cSJeff Layton } 15333c1c995cSJeff Layton 15345adfd885SJeff Layton static void release_lock_stateid(struct nfs4_ol_stateid *stp) 1535b49e084dSJeff Layton { 1536f46c445bSChuck Lever struct nfs4_client *clp = stp->st_stid.sc_client; 1537e8568739SJeff Layton bool unhashed; 15381c755dc1SJeff Layton 1539f46c445bSChuck Lever spin_lock(&clp->cl_lock); 1540e8568739SJeff Layton unhashed = unhash_lock_stateid(stp); 1541f46c445bSChuck Lever spin_unlock(&clp->cl_lock); 1542e8568739SJeff Layton if (unhashed) 15436011695dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 1544529d7b2aSJ. Bruce Fields } 1545529d7b2aSJ. Bruce Fields 1546c58c6610STrond Myklebust static void unhash_lockowner_locked(struct nfs4_lockowner *lo) 1547529d7b2aSJ. Bruce Fields { 1548d4f0489fSTrond Myklebust struct nfs4_client *clp = lo->lo_owner.so_client; 1549c58c6610STrond Myklebust 1550d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 1551c58c6610STrond Myklebust 15528f4b54c5SJeff Layton list_del_init(&lo->lo_owner.so_strhash); 15538f4b54c5SJeff Layton } 15548f4b54c5SJeff Layton 15552c41beb0SJeff Layton /* 15562c41beb0SJeff Layton * Free a list of generic stateids that were collected earlier after being 15572c41beb0SJeff Layton * fully unhashed. 15582c41beb0SJeff Layton */ 15592c41beb0SJeff Layton static void 15602c41beb0SJeff Layton free_ol_stateid_reaplist(struct list_head *reaplist) 15612c41beb0SJeff Layton { 15622c41beb0SJeff Layton struct nfs4_ol_stateid *stp; 1563fb94d766SKinglong Mee struct nfs4_file *fp; 15642c41beb0SJeff Layton 15652c41beb0SJeff Layton might_sleep(); 15662c41beb0SJeff Layton 15672c41beb0SJeff Layton while (!list_empty(reaplist)) { 15682c41beb0SJeff Layton stp = list_first_entry(reaplist, struct nfs4_ol_stateid, 15692c41beb0SJeff Layton st_locks); 15702c41beb0SJeff Layton list_del(&stp->st_locks); 1571fb94d766SKinglong Mee fp = stp->st_stid.sc_file; 15722c41beb0SJeff Layton stp->st_stid.sc_free(&stp->st_stid); 1573fb94d766SKinglong Mee if (fp) 1574fb94d766SKinglong Mee put_nfs4_file(fp); 15752c41beb0SJeff Layton } 15762c41beb0SJeff Layton } 15772c41beb0SJeff Layton 1578d83017f9SJeff Layton static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, 1579d83017f9SJeff Layton struct list_head *reaplist) 15803c87b9b7STrond Myklebust { 15813c87b9b7STrond Myklebust struct nfs4_ol_stateid *stp; 15823c87b9b7STrond Myklebust 1583e8568739SJeff Layton lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); 1584e8568739SJeff Layton 15853c87b9b7STrond Myklebust while (!list_empty(&open_stp->st_locks)) { 15863c87b9b7STrond Myklebust stp = list_entry(open_stp->st_locks.next, 15873c87b9b7STrond Myklebust struct nfs4_ol_stateid, st_locks); 1588e8568739SJeff Layton WARN_ON(!unhash_lock_stateid(stp)); 1589d83017f9SJeff Layton put_ol_stateid_locked(stp, reaplist); 1590529d7b2aSJ. Bruce Fields } 1591529d7b2aSJ. Bruce Fields } 1592529d7b2aSJ. Bruce Fields 1593e8568739SJeff Layton static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, 1594d83017f9SJeff Layton struct list_head *reaplist) 15952283963fSJ. Bruce Fields { 15962c41beb0SJeff Layton lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); 15972c41beb0SJeff Layton 1598a451b123STrond Myklebust if (!unhash_ol_stateid(stp)) 1599a451b123STrond Myklebust return false; 1600d83017f9SJeff Layton release_open_stateid_locks(stp, reaplist); 1601a451b123STrond Myklebust return true; 160238c387b5SJ. Bruce Fields } 160338c387b5SJ. Bruce Fields 160438c387b5SJ. Bruce Fields static void release_open_stateid(struct nfs4_ol_stateid *stp) 160538c387b5SJ. Bruce Fields { 16062c41beb0SJeff Layton LIST_HEAD(reaplist); 16072c41beb0SJeff Layton 16082c41beb0SJeff Layton spin_lock(&stp->st_stid.sc_client->cl_lock); 1609e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 16102c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 16112c41beb0SJeff Layton spin_unlock(&stp->st_stid.sc_client->cl_lock); 16122c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 16132283963fSJ. Bruce Fields } 16142283963fSJ. Bruce Fields 16157ffb5880STrond Myklebust static void unhash_openowner_locked(struct nfs4_openowner *oo) 1616f1d110caSJ. Bruce Fields { 1617d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 16187ffb5880STrond Myklebust 1619d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 16207ffb5880STrond Myklebust 16218f4b54c5SJeff Layton list_del_init(&oo->oo_owner.so_strhash); 16228f4b54c5SJeff Layton list_del_init(&oo->oo_perclient); 1623f1d110caSJ. Bruce Fields } 1624f1d110caSJ. Bruce Fields 1625f7a4d872SJ. Bruce Fields static void release_last_closed_stateid(struct nfs4_openowner *oo) 1626f7a4d872SJ. Bruce Fields { 1627217526e7SJeff Layton struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, 1628217526e7SJeff Layton nfsd_net_id); 1629217526e7SJeff Layton struct nfs4_ol_stateid *s; 1630f7a4d872SJ. Bruce Fields 1631217526e7SJeff Layton spin_lock(&nn->client_lock); 1632217526e7SJeff Layton s = oo->oo_last_closed_stid; 1633f7a4d872SJ. Bruce Fields if (s) { 1634d3134b10SJeff Layton list_del_init(&oo->oo_close_lru); 1635f7a4d872SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 1636f7a4d872SJ. Bruce Fields } 1637217526e7SJeff Layton spin_unlock(&nn->client_lock); 1638217526e7SJeff Layton if (s) 1639217526e7SJeff Layton nfs4_put_stid(&s->st_stid); 1640f7a4d872SJ. Bruce Fields } 1641f7a4d872SJ. Bruce Fields 16422c41beb0SJeff Layton static void release_openowner(struct nfs4_openowner *oo) 16438f4b54c5SJeff Layton { 16448f4b54c5SJeff Layton struct nfs4_ol_stateid *stp; 1645d4f0489fSTrond Myklebust struct nfs4_client *clp = oo->oo_owner.so_client; 16462c41beb0SJeff Layton struct list_head reaplist; 16477ffb5880STrond Myklebust 16482c41beb0SJeff Layton INIT_LIST_HEAD(&reaplist); 16497ffb5880STrond Myklebust 1650d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 16517ffb5880STrond Myklebust unhash_openowner_locked(oo); 16522c41beb0SJeff Layton while (!list_empty(&oo->oo_owner.so_stateids)) { 16532c41beb0SJeff Layton stp = list_first_entry(&oo->oo_owner.so_stateids, 16542c41beb0SJeff Layton struct nfs4_ol_stateid, st_perstateowner); 1655e8568739SJeff Layton if (unhash_open_stateid(stp, &reaplist)) 16562c41beb0SJeff Layton put_ol_stateid_locked(stp, &reaplist); 16572c41beb0SJeff Layton } 1658d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 16592c41beb0SJeff Layton free_ol_stateid_reaplist(&reaplist); 1660f7a4d872SJ. Bruce Fields release_last_closed_stateid(oo); 16616b180f0bSJeff Layton nfs4_put_stateowner(&oo->oo_owner); 1662f1d110caSJ. Bruce Fields } 1663f1d110caSJ. Bruce Fields 16645282fd72SMarc Eshel static inline int 16655282fd72SMarc Eshel hash_sessionid(struct nfs4_sessionid *sessionid) 16665282fd72SMarc Eshel { 16675282fd72SMarc Eshel struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; 16685282fd72SMarc Eshel 16695282fd72SMarc Eshel return sid->sequence % SESSION_HASH_SIZE; 16705282fd72SMarc Eshel } 16715282fd72SMarc Eshel 1672135dd002SMark Salter #ifdef CONFIG_SUNRPC_DEBUG 16735282fd72SMarc Eshel static inline void 16745282fd72SMarc Eshel dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 16755282fd72SMarc Eshel { 16765282fd72SMarc Eshel u32 *ptr = (u32 *)(&sessionid->data[0]); 16775282fd72SMarc Eshel dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); 16785282fd72SMarc Eshel } 16798f199b82STrond Myklebust #else 16808f199b82STrond Myklebust static inline void 16818f199b82STrond Myklebust dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) 16828f199b82STrond Myklebust { 16838f199b82STrond Myklebust } 16848f199b82STrond Myklebust #endif 16858f199b82STrond Myklebust 16869411b1d4SJ. Bruce Fields /* 16879411b1d4SJ. Bruce Fields * Bump the seqid on cstate->replay_owner, and clear replay_owner if it 16889411b1d4SJ. Bruce Fields * won't be used for replay. 16899411b1d4SJ. Bruce Fields */ 16909411b1d4SJ. Bruce Fields void nfsd4_bump_seqid(struct nfsd4_compound_state *cstate, __be32 nfserr) 16919411b1d4SJ. Bruce Fields { 16929411b1d4SJ. Bruce Fields struct nfs4_stateowner *so = cstate->replay_owner; 16939411b1d4SJ. Bruce Fields 16949411b1d4SJ. Bruce Fields if (nfserr == nfserr_replay_me) 16959411b1d4SJ. Bruce Fields return; 16969411b1d4SJ. Bruce Fields 16979411b1d4SJ. Bruce Fields if (!seqid_mutating_err(ntohl(nfserr))) { 169858fb12e6SJeff Layton nfsd4_cstate_clear_replay(cstate); 16999411b1d4SJ. Bruce Fields return; 17009411b1d4SJ. Bruce Fields } 17019411b1d4SJ. Bruce Fields if (!so) 17029411b1d4SJ. Bruce Fields return; 17039411b1d4SJ. Bruce Fields if (so->so_is_open_owner) 17049411b1d4SJ. Bruce Fields release_last_closed_stateid(openowner(so)); 17059411b1d4SJ. Bruce Fields so->so_seqid++; 17069411b1d4SJ. Bruce Fields return; 17079411b1d4SJ. Bruce Fields } 17085282fd72SMarc Eshel 1709ec6b5d7bSAndy Adamson static void 1710ec6b5d7bSAndy Adamson gen_sessionid(struct nfsd4_session *ses) 1711ec6b5d7bSAndy Adamson { 1712ec6b5d7bSAndy Adamson struct nfs4_client *clp = ses->se_client; 1713ec6b5d7bSAndy Adamson struct nfsd4_sessionid *sid; 1714ec6b5d7bSAndy Adamson 1715ec6b5d7bSAndy Adamson sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; 1716ec6b5d7bSAndy Adamson sid->clientid = clp->cl_clientid; 1717ec6b5d7bSAndy Adamson sid->sequence = current_sessionid++; 1718ec6b5d7bSAndy Adamson sid->reserved = 0; 1719ec6b5d7bSAndy Adamson } 1720ec6b5d7bSAndy Adamson 1721ec6b5d7bSAndy Adamson /* 1722a649637cSAndy Adamson * The protocol defines ca_maxresponssize_cached to include the size of 1723a649637cSAndy Adamson * the rpc header, but all we need to cache is the data starting after 1724a649637cSAndy Adamson * the end of the initial SEQUENCE operation--the rest we regenerate 1725a649637cSAndy Adamson * each time. Therefore we can advertise a ca_maxresponssize_cached 1726a649637cSAndy Adamson * value that is the number of bytes in our cache plus a few additional 1727a649637cSAndy Adamson * bytes. In order to stay on the safe side, and not promise more than 1728a649637cSAndy Adamson * we can cache, those additional bytes must be the minimum possible: 24 1729a649637cSAndy Adamson * bytes of rpc header (xid through accept state, with AUTH_NULL 1730a649637cSAndy Adamson * verifier), 12 for the compound header (with zero-length tag), and 44 1731a649637cSAndy Adamson * for the SEQUENCE op response: 1732ec6b5d7bSAndy Adamson */ 1733a649637cSAndy Adamson #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 1734a649637cSAndy Adamson 1735557ce264SAndy Adamson static void 1736557ce264SAndy Adamson free_session_slots(struct nfsd4_session *ses) 1737557ce264SAndy Adamson { 1738557ce264SAndy Adamson int i; 1739557ce264SAndy Adamson 174053da6a53SJ. Bruce Fields for (i = 0; i < ses->se_fchannel.maxreqs; i++) { 174153da6a53SJ. Bruce Fields free_svc_cred(&ses->se_slots[i]->sl_cred); 1742557ce264SAndy Adamson kfree(ses->se_slots[i]); 1743557ce264SAndy Adamson } 174453da6a53SJ. Bruce Fields } 1745557ce264SAndy Adamson 1746efe0cb6dSJ. Bruce Fields /* 1747efe0cb6dSJ. Bruce Fields * We don't actually need to cache the rpc and session headers, so we 1748efe0cb6dSJ. Bruce Fields * can allocate a little less for each slot: 1749efe0cb6dSJ. Bruce Fields */ 175055c760cfSJ. Bruce Fields static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) 1751efe0cb6dSJ. Bruce Fields { 175255c760cfSJ. Bruce Fields u32 size; 1753efe0cb6dSJ. Bruce Fields 175455c760cfSJ. Bruce Fields if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) 175555c760cfSJ. Bruce Fields size = 0; 175655c760cfSJ. Bruce Fields else 175755c760cfSJ. Bruce Fields size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 175855c760cfSJ. Bruce Fields return size + sizeof(struct nfsd4_slot); 1759557ce264SAndy Adamson } 1760557ce264SAndy Adamson 17615b6feee9SJ. Bruce Fields /* 17625b6feee9SJ. Bruce Fields * XXX: If we run out of reserved DRC memory we could (up to a point) 17635b6feee9SJ. Bruce Fields * re-negotiate active sessions and reduce their slot usage to make 176442b2aa86SJustin P. Mattock * room for new connections. For now we just fail the create session. 17655b6feee9SJ. Bruce Fields */ 17662030ca56SNeilBrown static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 17675b6feee9SJ. Bruce Fields { 176855c760cfSJ. Bruce Fields u32 slotsize = slot_bytes(ca); 176955c760cfSJ. Bruce Fields u32 num = ca->maxreqs; 1770c54f24e3SJ. Bruce Fields unsigned long avail, total_avail; 17712030ca56SNeilBrown unsigned int scale_factor; 17725b6feee9SJ. Bruce Fields 17735b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 17747f49fd5dSNeilBrown if (nfsd_drc_max_mem > nfsd_drc_mem_used) 1775c54f24e3SJ. Bruce Fields total_avail = nfsd_drc_max_mem - nfsd_drc_mem_used; 17767f49fd5dSNeilBrown else 17777f49fd5dSNeilBrown /* We have handed out more space than we chose in 17787f49fd5dSNeilBrown * set_max_drc() to allow. That isn't really a 17797f49fd5dSNeilBrown * problem as long as that doesn't make us think we 17807f49fd5dSNeilBrown * have lots more due to integer overflow. 17817f49fd5dSNeilBrown */ 17827f49fd5dSNeilBrown total_avail = 0; 1783c54f24e3SJ. Bruce Fields avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, total_avail); 1784de766e57SJ. Bruce Fields /* 17852030ca56SNeilBrown * Never use more than a fraction of the remaining memory, 17867f49fd5dSNeilBrown * unless it's the only way to give this client a slot. 17872030ca56SNeilBrown * The chosen fraction is either 1/8 or 1/number of threads, 17882030ca56SNeilBrown * whichever is smaller. This ensures there are adequate 17892030ca56SNeilBrown * slots to support multiple clients per thread. 17907f49fd5dSNeilBrown * Give the client one slot even if that would require 17917f49fd5dSNeilBrown * over-allocation--it is better than failure. 1792de766e57SJ. Bruce Fields */ 17932030ca56SNeilBrown scale_factor = max_t(unsigned int, 8, nn->nfsd_serv->sv_nrthreads); 17942030ca56SNeilBrown 17952030ca56SNeilBrown avail = clamp_t(unsigned long, avail, slotsize, 17962030ca56SNeilBrown total_avail/scale_factor); 17975b6feee9SJ. Bruce Fields num = min_t(int, num, avail / slotsize); 17987f49fd5dSNeilBrown num = max_t(int, num, 1); 17995b6feee9SJ. Bruce Fields nfsd_drc_mem_used += num * slotsize; 18005b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 18015b6feee9SJ. Bruce Fields 18025b6feee9SJ. Bruce Fields return num; 18035b6feee9SJ. Bruce Fields } 18045b6feee9SJ. Bruce Fields 180555c760cfSJ. Bruce Fields static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 18065b6feee9SJ. Bruce Fields { 180755c760cfSJ. Bruce Fields int slotsize = slot_bytes(ca); 180855c760cfSJ. Bruce Fields 18095b6feee9SJ. Bruce Fields spin_lock(&nfsd_drc_lock); 181055c760cfSJ. Bruce Fields nfsd_drc_mem_used -= slotsize * ca->maxreqs; 18115b6feee9SJ. Bruce Fields spin_unlock(&nfsd_drc_lock); 18125b6feee9SJ. Bruce Fields } 18135b6feee9SJ. Bruce Fields 181460810e54SKinglong Mee static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, 181560810e54SKinglong Mee struct nfsd4_channel_attrs *battrs) 18165b6feee9SJ. Bruce Fields { 181760810e54SKinglong Mee int numslots = fattrs->maxreqs; 181860810e54SKinglong Mee int slotsize = slot_bytes(fattrs); 18195b6feee9SJ. Bruce Fields struct nfsd4_session *new; 182085a0d0c9SXiu Jianfeng int i; 1821ec6b5d7bSAndy Adamson 182285a0d0c9SXiu Jianfeng BUILD_BUG_ON(struct_size(new, se_slots, NFSD_MAX_SLOTS_PER_SESSION) 182385a0d0c9SXiu Jianfeng > PAGE_SIZE); 1824ec6b5d7bSAndy Adamson 182585a0d0c9SXiu Jianfeng new = kzalloc(struct_size(new, se_slots, numslots), GFP_KERNEL); 18266c18ba9fSAlexandros Batsakis if (!new) 18275b6feee9SJ. Bruce Fields return NULL; 1828ec6b5d7bSAndy Adamson /* allocate each struct nfsd4_slot and data cache in one piece */ 18295b6feee9SJ. Bruce Fields for (i = 0; i < numslots; i++) { 183055c760cfSJ. Bruce Fields new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 18315b6feee9SJ. Bruce Fields if (!new->se_slots[i]) 1832ec6b5d7bSAndy Adamson goto out_free; 1833ec6b5d7bSAndy Adamson } 183460810e54SKinglong Mee 183560810e54SKinglong Mee memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs)); 183660810e54SKinglong Mee memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs)); 183760810e54SKinglong Mee 18385b6feee9SJ. Bruce Fields return new; 18395b6feee9SJ. Bruce Fields out_free: 18405b6feee9SJ. Bruce Fields while (i--) 18415b6feee9SJ. Bruce Fields kfree(new->se_slots[i]); 18425b6feee9SJ. Bruce Fields kfree(new); 18435b6feee9SJ. Bruce Fields return NULL; 18445b6feee9SJ. Bruce Fields } 18455b6feee9SJ. Bruce Fields 184619cf5c02SJ. Bruce Fields static void free_conn(struct nfsd4_conn *c) 184719cf5c02SJ. Bruce Fields { 184819cf5c02SJ. Bruce Fields svc_xprt_put(c->cn_xprt); 184919cf5c02SJ. Bruce Fields kfree(c); 185019cf5c02SJ. Bruce Fields } 185119cf5c02SJ. Bruce Fields 185219cf5c02SJ. Bruce Fields static void nfsd4_conn_lost(struct svc_xpt_user *u) 185319cf5c02SJ. Bruce Fields { 185419cf5c02SJ. Bruce Fields struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); 185519cf5c02SJ. Bruce Fields struct nfs4_client *clp = c->cn_session->se_client; 185619cf5c02SJ. Bruce Fields 1857806d65b6SChuck Lever trace_nfsd_cb_lost(clp); 1858806d65b6SChuck Lever 185919cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 186019cf5c02SJ. Bruce Fields if (!list_empty(&c->cn_persession)) { 186119cf5c02SJ. Bruce Fields list_del(&c->cn_persession); 186219cf5c02SJ. Bruce Fields free_conn(c); 186319cf5c02SJ. Bruce Fields } 1864eea49806SJ. Bruce Fields nfsd4_probe_callback(clp); 18652e4b7239SJ. Bruce Fields spin_unlock(&clp->cl_lock); 186619cf5c02SJ. Bruce Fields } 186719cf5c02SJ. Bruce Fields 1868d29c374cSJ. Bruce Fields static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags) 1869c7662518SJ. Bruce Fields { 1870c7662518SJ. Bruce Fields struct nfsd4_conn *conn; 1871c7662518SJ. Bruce Fields 1872c7662518SJ. Bruce Fields conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL); 1873c7662518SJ. Bruce Fields if (!conn) 1874db90681dSJ. Bruce Fields return NULL; 1875c7662518SJ. Bruce Fields svc_xprt_get(rqstp->rq_xprt); 1876c7662518SJ. Bruce Fields conn->cn_xprt = rqstp->rq_xprt; 1877d29c374cSJ. Bruce Fields conn->cn_flags = flags; 1878db90681dSJ. Bruce Fields INIT_LIST_HEAD(&conn->cn_xpt_user.list); 1879db90681dSJ. Bruce Fields return conn; 1880db90681dSJ. Bruce Fields } 1881db90681dSJ. Bruce Fields 1882328ead28SJ. Bruce Fields static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1883328ead28SJ. Bruce Fields { 1884328ead28SJ. Bruce Fields conn->cn_session = ses; 1885328ead28SJ. Bruce Fields list_add(&conn->cn_persession, &ses->se_conns); 1886328ead28SJ. Bruce Fields } 1887328ead28SJ. Bruce Fields 1888db90681dSJ. Bruce Fields static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses) 1889db90681dSJ. Bruce Fields { 1890db90681dSJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 1891c7662518SJ. Bruce Fields 1892c7662518SJ. Bruce Fields spin_lock(&clp->cl_lock); 1893328ead28SJ. Bruce Fields __nfsd4_hash_conn(conn, ses); 1894c7662518SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1895db90681dSJ. Bruce Fields } 1896c7662518SJ. Bruce Fields 189721b75b01SJ. Bruce Fields static int nfsd4_register_conn(struct nfsd4_conn *conn) 1898db90681dSJ. Bruce Fields { 189919cf5c02SJ. Bruce Fields conn->cn_xpt_user.callback = nfsd4_conn_lost; 190021b75b01SJ. Bruce Fields return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); 1901db90681dSJ. Bruce Fields } 1902db90681dSJ. Bruce Fields 1903e1ff371fSJ. Bruce Fields static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) 1904db90681dSJ. Bruce Fields { 190521b75b01SJ. Bruce Fields int ret; 1906db90681dSJ. Bruce Fields 1907db90681dSJ. Bruce Fields nfsd4_hash_conn(conn, ses); 190821b75b01SJ. Bruce Fields ret = nfsd4_register_conn(conn); 190921b75b01SJ. Bruce Fields if (ret) 191021b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 191121b75b01SJ. Bruce Fields nfsd4_conn_lost(&conn->cn_xpt_user); 191257a37144SJ. Bruce Fields /* We may have gained or lost a callback channel: */ 191357a37144SJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 1914c7662518SJ. Bruce Fields } 1915c7662518SJ. Bruce Fields 1916e1ff371fSJ. Bruce Fields static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) 19171d1bc8f2SJ. Bruce Fields { 19181d1bc8f2SJ. Bruce Fields u32 dir = NFS4_CDFC4_FORE; 19191d1bc8f2SJ. Bruce Fields 1920e1ff371fSJ. Bruce Fields if (cses->flags & SESSION4_BACK_CHAN) 19211d1bc8f2SJ. Bruce Fields dir |= NFS4_CDFC4_BACK; 1922e1ff371fSJ. Bruce Fields return alloc_conn(rqstp, dir); 19231d1bc8f2SJ. Bruce Fields } 19241d1bc8f2SJ. Bruce Fields 19251d1bc8f2SJ. Bruce Fields /* must be called under client_lock */ 192619cf5c02SJ. Bruce Fields static void nfsd4_del_conns(struct nfsd4_session *s) 1927c7662518SJ. Bruce Fields { 192819cf5c02SJ. Bruce Fields struct nfs4_client *clp = s->se_client; 192919cf5c02SJ. Bruce Fields struct nfsd4_conn *c; 193019cf5c02SJ. Bruce Fields 193119cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 193219cf5c02SJ. Bruce Fields while (!list_empty(&s->se_conns)) { 193319cf5c02SJ. Bruce Fields c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession); 193419cf5c02SJ. Bruce Fields list_del_init(&c->cn_persession); 193519cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 193619cf5c02SJ. Bruce Fields 193719cf5c02SJ. Bruce Fields unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user); 193819cf5c02SJ. Bruce Fields free_conn(c); 193919cf5c02SJ. Bruce Fields 194019cf5c02SJ. Bruce Fields spin_lock(&clp->cl_lock); 194119cf5c02SJ. Bruce Fields } 194219cf5c02SJ. Bruce Fields spin_unlock(&clp->cl_lock); 1943c7662518SJ. Bruce Fields } 1944c7662518SJ. Bruce Fields 19451377b69eSJ. Bruce Fields static void __free_session(struct nfsd4_session *ses) 19461377b69eSJ. Bruce Fields { 19471377b69eSJ. Bruce Fields free_session_slots(ses); 19481377b69eSJ. Bruce Fields kfree(ses); 19491377b69eSJ. Bruce Fields } 19501377b69eSJ. Bruce Fields 195166b2b9b2SJ. Bruce Fields static void free_session(struct nfsd4_session *ses) 1952508dc6e1SBenny Halevy { 1953c7662518SJ. Bruce Fields nfsd4_del_conns(ses); 195455c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&ses->se_fchannel); 1955c7662518SJ. Bruce Fields __free_session(ses); 1956a827bcb2SJ. Bruce Fields } 1957ec6b5d7bSAndy Adamson 1958135ae827SFengguang Wu static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 1959a827bcb2SJ. Bruce Fields { 1960a827bcb2SJ. Bruce Fields int idx; 19611872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1962a827bcb2SJ. Bruce Fields 1963ec6b5d7bSAndy Adamson new->se_client = clp; 1964ec6b5d7bSAndy Adamson gen_sessionid(new); 1965ec6b5d7bSAndy Adamson 1966c7662518SJ. Bruce Fields INIT_LIST_HEAD(&new->se_conns); 1967c7662518SJ. Bruce Fields 1968ac7c46f2SJ. Bruce Fields new->se_cb_seq_nr = 1; 1969ec6b5d7bSAndy Adamson new->se_flags = cses->flags; 19708b5ce5cdSJ. Bruce Fields new->se_cb_prog = cses->callback_prog; 1971c6bb3ca2SJ. Bruce Fields new->se_cb_sec = cses->cb_sec; 197266b2b9b2SJ. Bruce Fields atomic_set(&new->se_ref, 0); 19735b6feee9SJ. Bruce Fields idx = hash_sessionid(&new->se_sessionid); 19741872de0eSStanislav Kinsbursky list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); 19754c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 1976ec6b5d7bSAndy Adamson list_add(&new->se_perclnt, &clp->cl_sessions); 19774c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 197860810e54SKinglong Mee 1979b0d2e42cSChuck Lever { 1980edd76786SJ. Bruce Fields struct sockaddr *sa = svc_addr(rqstp); 1981dcbeaa68SJ. Bruce Fields /* 1982dcbeaa68SJ. Bruce Fields * This is a little silly; with sessions there's no real 1983dcbeaa68SJ. Bruce Fields * use for the callback address. Use the peer address 1984dcbeaa68SJ. Bruce Fields * as a reasonable default for now, but consider fixing 1985dcbeaa68SJ. Bruce Fields * the rpc client not to require an address in the 1986dcbeaa68SJ. Bruce Fields * future: 1987dcbeaa68SJ. Bruce Fields */ 1988edd76786SJ. Bruce Fields rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); 1989edd76786SJ. Bruce Fields clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); 1990edd76786SJ. Bruce Fields } 1991ec6b5d7bSAndy Adamson } 1992ec6b5d7bSAndy Adamson 19939089f1b4SBenny Halevy /* caller must hold client_lock */ 19945282fd72SMarc Eshel static struct nfsd4_session * 1995d4e19e70STrond Myklebust __find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) 19965282fd72SMarc Eshel { 19975282fd72SMarc Eshel struct nfsd4_session *elem; 19985282fd72SMarc Eshel int idx; 19991872de0eSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 20005282fd72SMarc Eshel 20010a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20020a880a28STrond Myklebust 20035282fd72SMarc Eshel dump_sessionid(__func__, sessionid); 20045282fd72SMarc Eshel idx = hash_sessionid(sessionid); 20055282fd72SMarc Eshel /* Search in the appropriate list */ 20061872de0eSStanislav Kinsbursky list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { 20075282fd72SMarc Eshel if (!memcmp(elem->se_sessionid.data, sessionid->data, 20085282fd72SMarc Eshel NFS4_MAX_SESSIONID_LEN)) { 20095282fd72SMarc Eshel return elem; 20105282fd72SMarc Eshel } 20115282fd72SMarc Eshel } 20125282fd72SMarc Eshel 20135282fd72SMarc Eshel dprintk("%s: session not found\n", __func__); 20145282fd72SMarc Eshel return NULL; 20155282fd72SMarc Eshel } 20165282fd72SMarc Eshel 2017d4e19e70STrond Myklebust static struct nfsd4_session * 2018d4e19e70STrond Myklebust find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net, 2019d4e19e70STrond Myklebust __be32 *ret) 2020d4e19e70STrond Myklebust { 2021d4e19e70STrond Myklebust struct nfsd4_session *session; 2022d4e19e70STrond Myklebust __be32 status = nfserr_badsession; 2023d4e19e70STrond Myklebust 2024d4e19e70STrond Myklebust session = __find_in_sessionid_hashtbl(sessionid, net); 2025d4e19e70STrond Myklebust if (!session) 2026d4e19e70STrond Myklebust goto out; 2027d4e19e70STrond Myklebust status = nfsd4_get_session_locked(session); 2028d4e19e70STrond Myklebust if (status) 2029d4e19e70STrond Myklebust session = NULL; 2030d4e19e70STrond Myklebust out: 2031d4e19e70STrond Myklebust *ret = status; 2032d4e19e70STrond Myklebust return session; 2033d4e19e70STrond Myklebust } 2034d4e19e70STrond Myklebust 20359089f1b4SBenny Halevy /* caller must hold client_lock */ 20367116ed6bSAndy Adamson static void 20375282fd72SMarc Eshel unhash_session(struct nfsd4_session *ses) 20387116ed6bSAndy Adamson { 20390a880a28STrond Myklebust struct nfs4_client *clp = ses->se_client; 20400a880a28STrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 20410a880a28STrond Myklebust 20420a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 20430a880a28STrond Myklebust 20447116ed6bSAndy Adamson list_del(&ses->se_hash); 20454c649378SJ. Bruce Fields spin_lock(&ses->se_client->cl_lock); 20467116ed6bSAndy Adamson list_del(&ses->se_perclnt); 20474c649378SJ. Bruce Fields spin_unlock(&ses->se_client->cl_lock); 20485282fd72SMarc Eshel } 20495282fd72SMarc Eshel 20501da177e4SLinus Torvalds /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ 20511da177e4SLinus Torvalds static int 20522c142baaSStanislav Kinsbursky STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) 20531da177e4SLinus Torvalds { 2054bbc7f33aSJ. Bruce Fields /* 2055bbc7f33aSJ. Bruce Fields * We're assuming the clid was not given out from a boot 2056bbc7f33aSJ. Bruce Fields * precisely 2^32 (about 136 years) before this one. That seems 2057bbc7f33aSJ. Bruce Fields * a safe assumption: 2058bbc7f33aSJ. Bruce Fields */ 2059bbc7f33aSJ. Bruce Fields if (clid->cl_boot == (u32)nn->boot_time) 20601da177e4SLinus Torvalds return 0; 2061dd5e3fbcSChuck Lever trace_nfsd_clid_stale(clid); 20621da177e4SLinus Torvalds return 1; 20631da177e4SLinus Torvalds } 20641da177e4SLinus Torvalds 20651da177e4SLinus Torvalds /* 20661da177e4SLinus Torvalds * XXX Should we use a slab cache ? 20671da177e4SLinus Torvalds * This type of memory management is somewhat inefficient, but we use it 20681da177e4SLinus Torvalds * anyway since SETCLIENTID is not a common operation. 20691da177e4SLinus Torvalds */ 20700926c395SDai Ngo static struct nfs4_client *alloc_client(struct xdr_netobj name, 20710926c395SDai Ngo struct nfsd_net *nn) 20721da177e4SLinus Torvalds { 20731da177e4SLinus Torvalds struct nfs4_client *clp; 2074d4f0489fSTrond Myklebust int i; 20751da177e4SLinus Torvalds 20764271c2c0SDai Ngo if (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) { 20774271c2c0SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 20784271c2c0SDai Ngo return NULL; 20794271c2c0SDai Ngo } 20809258a2d5SJeff Layton clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); 208135bba9a3SJ. Bruce Fields if (clp == NULL) 208235bba9a3SJ. Bruce Fields return NULL; 20836f4859b8SJ. Bruce Fields xdr_netobj_dup(&clp->cl_name, &name, GFP_KERNEL); 2084d4f0489fSTrond Myklebust if (clp->cl_name.data == NULL) 2085d4f0489fSTrond Myklebust goto err_no_name; 20866da2ec56SKees Cook clp->cl_ownerstr_hashtbl = kmalloc_array(OWNER_HASH_SIZE, 20876da2ec56SKees Cook sizeof(struct list_head), 20886da2ec56SKees Cook GFP_KERNEL); 2089d4f0489fSTrond Myklebust if (!clp->cl_ownerstr_hashtbl) 2090d4f0489fSTrond Myklebust goto err_no_hashtbl; 2091d4f0489fSTrond Myklebust for (i = 0; i < OWNER_HASH_SIZE; i++) 2092d4f0489fSTrond Myklebust INIT_LIST_HEAD(&clp->cl_ownerstr_hashtbl[i]); 20935694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_sessions); 20945694c93eSTrond Myklebust idr_init(&clp->cl_stateids); 209514ed14ccSJ. Bruce Fields atomic_set(&clp->cl_rpc_users, 0); 20965694c93eSTrond Myklebust clp->cl_cb_state = NFSD4_CB_UNKNOWN; 209766af2579SDai Ngo clp->cl_state = NFSD4_ACTIVE; 20980926c395SDai Ngo atomic_inc(&nn->nfs4_client_count); 209966af2579SDai Ngo atomic_set(&clp->cl_delegs_in_recall, 0); 21005694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_idhash); 21015694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_openowners); 21025694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_delegations); 21035694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_lru); 21045694c93eSTrond Myklebust INIT_LIST_HEAD(&clp->cl_revoked); 21059cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 21069cf514ccSChristoph Hellwig INIT_LIST_HEAD(&clp->cl_lo_states); 21079cf514ccSChristoph Hellwig #endif 2108e0639dc5SOlga Kornievskaia INIT_LIST_HEAD(&clp->async_copies); 2109e0639dc5SOlga Kornievskaia spin_lock_init(&clp->async_lock); 21105694c93eSTrond Myklebust spin_lock_init(&clp->cl_lock); 21115694c93eSTrond Myklebust rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 21121da177e4SLinus Torvalds return clp; 2113d4f0489fSTrond Myklebust err_no_hashtbl: 2114d4f0489fSTrond Myklebust kfree(clp->cl_name.data); 2115d4f0489fSTrond Myklebust err_no_name: 21169258a2d5SJeff Layton kmem_cache_free(client_slab, clp); 2117d4f0489fSTrond Myklebust return NULL; 21181da177e4SLinus Torvalds } 21191da177e4SLinus Torvalds 212059f8e91bSJ. Bruce Fields static void __free_client(struct kref *k) 212159f8e91bSJ. Bruce Fields { 2122e8a79fb1SJ. Bruce Fields struct nfsdfs_client *c = container_of(k, struct nfsdfs_client, cl_ref); 2123e8a79fb1SJ. Bruce Fields struct nfs4_client *clp = container_of(c, struct nfs4_client, cl_nfsdfs); 212459f8e91bSJ. Bruce Fields 212559f8e91bSJ. Bruce Fields free_svc_cred(&clp->cl_cred); 212659f8e91bSJ. Bruce Fields kfree(clp->cl_ownerstr_hashtbl); 212759f8e91bSJ. Bruce Fields kfree(clp->cl_name.data); 212879123444SJ. Bruce Fields kfree(clp->cl_nii_domain.data); 212979123444SJ. Bruce Fields kfree(clp->cl_nii_name.data); 213059f8e91bSJ. Bruce Fields idr_destroy(&clp->cl_stateids); 213144df6f43SDai Ngo kfree(clp->cl_ra); 213259f8e91bSJ. Bruce Fields kmem_cache_free(client_slab, clp); 213359f8e91bSJ. Bruce Fields } 213459f8e91bSJ. Bruce Fields 2135297e57a2SYueHaibing static void drop_client(struct nfs4_client *clp) 213659f8e91bSJ. Bruce Fields { 2137e8a79fb1SJ. Bruce Fields kref_put(&clp->cl_nfsdfs.cl_ref, __free_client); 213859f8e91bSJ. Bruce Fields } 213959f8e91bSJ. Bruce Fields 21404dd86e15STrond Myklebust static void 21411da177e4SLinus Torvalds free_client(struct nfs4_client *clp) 21421da177e4SLinus Torvalds { 2143792c95ddSJ. Bruce Fields while (!list_empty(&clp->cl_sessions)) { 2144792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2145792c95ddSJ. Bruce Fields ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, 2146792c95ddSJ. Bruce Fields se_perclnt); 2147792c95ddSJ. Bruce Fields list_del(&ses->se_perclnt); 214866b2b9b2SJ. Bruce Fields WARN_ON_ONCE(atomic_read(&ses->se_ref)); 214966b2b9b2SJ. Bruce Fields free_session(ses); 2150792c95ddSJ. Bruce Fields } 21514cb57e30STrond Myklebust rpc_destroy_wait_queue(&clp->cl_cb_waitq); 215289c905beSJ. Bruce Fields if (clp->cl_nfsd_dentry) { 2153e8a79fb1SJ. Bruce Fields nfsd_client_rmdir(clp->cl_nfsd_dentry); 215489c905beSJ. Bruce Fields clp->cl_nfsd_dentry = NULL; 215589c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 215689c905beSJ. Bruce Fields } 215759f8e91bSJ. Bruce Fields drop_client(clp); 21581da177e4SLinus Torvalds } 21591da177e4SLinus Torvalds 216084d38ac9SBenny Halevy /* must be called under the client_lock */ 21614beb345bSTrond Myklebust static void 216284d38ac9SBenny Halevy unhash_client_locked(struct nfs4_client *clp) 216384d38ac9SBenny Halevy { 21644beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2165792c95ddSJ. Bruce Fields struct nfsd4_session *ses; 2166792c95ddSJ. Bruce Fields 21670a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 21680a880a28STrond Myklebust 21694beb345bSTrond Myklebust /* Mark the client as expired! */ 21704beb345bSTrond Myklebust clp->cl_time = 0; 21714beb345bSTrond Myklebust /* Make it invisible */ 21724beb345bSTrond Myklebust if (!list_empty(&clp->cl_idhash)) { 21734beb345bSTrond Myklebust list_del_init(&clp->cl_idhash); 21744beb345bSTrond Myklebust if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 21754beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->conf_name_tree); 21764beb345bSTrond Myklebust else 21774beb345bSTrond Myklebust rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 21784beb345bSTrond Myklebust } 21794beb345bSTrond Myklebust list_del_init(&clp->cl_lru); 21804c649378SJ. Bruce Fields spin_lock(&clp->cl_lock); 2181792c95ddSJ. Bruce Fields list_for_each_entry(ses, &clp->cl_sessions, se_perclnt) 2182792c95ddSJ. Bruce Fields list_del_init(&ses->se_hash); 21834c649378SJ. Bruce Fields spin_unlock(&clp->cl_lock); 218484d38ac9SBenny Halevy } 218584d38ac9SBenny Halevy 21861da177e4SLinus Torvalds static void 21874beb345bSTrond Myklebust unhash_client(struct nfs4_client *clp) 21884beb345bSTrond Myklebust { 21894beb345bSTrond Myklebust struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 21904beb345bSTrond Myklebust 21914beb345bSTrond Myklebust spin_lock(&nn->client_lock); 21924beb345bSTrond Myklebust unhash_client_locked(clp); 21934beb345bSTrond Myklebust spin_unlock(&nn->client_lock); 21944beb345bSTrond Myklebust } 21954beb345bSTrond Myklebust 219697403d95SJeff Layton static __be32 mark_client_expired_locked(struct nfs4_client *clp) 219797403d95SJeff Layton { 219814ed14ccSJ. Bruce Fields if (atomic_read(&clp->cl_rpc_users)) 219997403d95SJeff Layton return nfserr_jukebox; 220097403d95SJeff Layton unhash_client_locked(clp); 220197403d95SJeff Layton return nfs_ok; 220297403d95SJeff Layton } 220397403d95SJeff Layton 22044beb345bSTrond Myklebust static void 22054beb345bSTrond Myklebust __destroy_client(struct nfs4_client *clp) 22061da177e4SLinus Torvalds { 22070926c395SDai Ngo struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 220868ef3bc3SJeff Layton int i; 2209fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 22101da177e4SLinus Torvalds struct nfs4_delegation *dp; 22111da177e4SLinus Torvalds struct list_head reaplist; 22121da177e4SLinus Torvalds 22131da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 2214cdc97505SBenny Halevy spin_lock(&state_lock); 2215ea1da636SNeilBrown while (!list_empty(&clp->cl_delegations)) { 2216ea1da636SNeilBrown dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 22173fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 221842690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 22191da177e4SLinus Torvalds } 2220cdc97505SBenny Halevy spin_unlock(&state_lock); 22211da177e4SLinus Torvalds while (!list_empty(&reaplist)) { 22221da177e4SLinus Torvalds dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 222342690676SJeff Layton list_del_init(&dp->dl_recall_lru); 22240af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 22251da177e4SLinus Torvalds } 22262d4a532dSJeff Layton while (!list_empty(&clp->cl_revoked)) { 2227c876486bSAndrew Elble dp = list_entry(clp->cl_revoked.next, struct nfs4_delegation, dl_recall_lru); 22282d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 22296011695dSTrond Myklebust nfs4_put_stid(&dp->dl_stid); 2230956c4feeSBenny Halevy } 2231ea1da636SNeilBrown while (!list_empty(&clp->cl_openowners)) { 2232fe0750e5SJ. Bruce Fields oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); 2233b5971afaSKinglong Mee nfs4_get_stateowner(&oo->oo_owner); 2234fe0750e5SJ. Bruce Fields release_openowner(oo); 22351da177e4SLinus Torvalds } 223668ef3bc3SJeff Layton for (i = 0; i < OWNER_HASH_SIZE; i++) { 223768ef3bc3SJeff Layton struct nfs4_stateowner *so, *tmp; 223868ef3bc3SJeff Layton 223968ef3bc3SJeff Layton list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], 224068ef3bc3SJeff Layton so_strhash) { 224168ef3bc3SJeff Layton /* Should be no openowners at this point */ 224268ef3bc3SJeff Layton WARN_ON_ONCE(so->so_is_open_owner); 224368ef3bc3SJeff Layton remove_blocked_locks(lockowner(so)); 224468ef3bc3SJeff Layton } 224568ef3bc3SJeff Layton } 22469cf514ccSChristoph Hellwig nfsd4_return_all_client_layouts(clp); 2247e0639dc5SOlga Kornievskaia nfsd4_shutdown_copy(clp); 22486ff8da08SJ. Bruce Fields nfsd4_shutdown_callback(clp); 22492bf23875SJ. Bruce Fields if (clp->cl_cb_conn.cb_xprt) 22502bf23875SJ. Bruce Fields svc_xprt_put(clp->cl_cb_conn.cb_xprt); 22510926c395SDai Ngo atomic_add_unless(&nn->nfs4_client_count, -1, 0); 22523a4ea23dSDai Ngo nfsd4_dec_courtesy_client_count(nn, clp); 2253b12a05cbSJ. Bruce Fields free_client(clp); 225489c905beSJ. Bruce Fields wake_up_all(&expiry_wq); 22551da177e4SLinus Torvalds } 22561da177e4SLinus Torvalds 22574beb345bSTrond Myklebust static void 22584beb345bSTrond Myklebust destroy_client(struct nfs4_client *clp) 22594beb345bSTrond Myklebust { 22604beb345bSTrond Myklebust unhash_client(clp); 22614beb345bSTrond Myklebust __destroy_client(clp); 22624beb345bSTrond Myklebust } 22634beb345bSTrond Myklebust 2264362063a5SScott Mayhew static void inc_reclaim_complete(struct nfs4_client *clp) 2265362063a5SScott Mayhew { 2266362063a5SScott Mayhew struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 2267362063a5SScott Mayhew 2268362063a5SScott Mayhew if (!nn->track_reclaim_completes) 2269362063a5SScott Mayhew return; 2270362063a5SScott Mayhew if (!nfsd4_find_reclaim_client(clp->cl_name, nn)) 2271362063a5SScott Mayhew return; 2272362063a5SScott Mayhew if (atomic_inc_return(&nn->nr_reclaim_complete) == 2273362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) { 2274362063a5SScott Mayhew printk(KERN_INFO "NFSD: all clients done reclaiming, ending NFSv4 grace period (net %x)\n", 2275362063a5SScott Mayhew clp->net->ns.inum); 2276362063a5SScott Mayhew nfsd4_end_grace(nn); 2277362063a5SScott Mayhew } 2278362063a5SScott Mayhew } 2279362063a5SScott Mayhew 22800d22f68fSJ. Bruce Fields static void expire_client(struct nfs4_client *clp) 22810d22f68fSJ. Bruce Fields { 22824beb345bSTrond Myklebust unhash_client(clp); 22830d22f68fSJ. Bruce Fields nfsd4_client_record_remove(clp); 22844beb345bSTrond Myklebust __destroy_client(clp); 22850d22f68fSJ. Bruce Fields } 22860d22f68fSJ. Bruce Fields 228735bba9a3SJ. Bruce Fields static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) 228835bba9a3SJ. Bruce Fields { 228935bba9a3SJ. Bruce Fields memcpy(target->cl_verifier.data, source->data, 229035bba9a3SJ. Bruce Fields sizeof(target->cl_verifier.data)); 22911da177e4SLinus Torvalds } 22921da177e4SLinus Torvalds 229335bba9a3SJ. Bruce Fields static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) 229435bba9a3SJ. Bruce Fields { 22951da177e4SLinus Torvalds target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 22961da177e4SLinus Torvalds target->cl_clientid.cl_id = source->cl_clientid.cl_id; 22971da177e4SLinus Torvalds } 22981da177e4SLinus Torvalds 229950043859SJ. Bruce Fields static int copy_cred(struct svc_cred *target, struct svc_cred *source) 230050043859SJ. Bruce Fields { 23012f10fdcbSNeilBrown target->cr_principal = kstrdup(source->cr_principal, GFP_KERNEL); 23022f10fdcbSNeilBrown target->cr_raw_principal = kstrdup(source->cr_raw_principal, 23032f10fdcbSNeilBrown GFP_KERNEL); 23049abdda5dSChuck Lever target->cr_targ_princ = kstrdup(source->cr_targ_princ, GFP_KERNEL); 23052f10fdcbSNeilBrown if ((source->cr_principal && !target->cr_principal) || 23069abdda5dSChuck Lever (source->cr_raw_principal && !target->cr_raw_principal) || 23079abdda5dSChuck Lever (source->cr_targ_princ && !target->cr_targ_princ)) 23082f10fdcbSNeilBrown return -ENOMEM; 230950043859SJ. Bruce Fields 2310d5497fc6SJ. Bruce Fields target->cr_flavor = source->cr_flavor; 23111da177e4SLinus Torvalds target->cr_uid = source->cr_uid; 23121da177e4SLinus Torvalds target->cr_gid = source->cr_gid; 23131da177e4SLinus Torvalds target->cr_group_info = source->cr_group_info; 23141da177e4SLinus Torvalds get_group_info(target->cr_group_info); 23150dc1531aSJ. Bruce Fields target->cr_gss_mech = source->cr_gss_mech; 23160dc1531aSJ. Bruce Fields if (source->cr_gss_mech) 23170dc1531aSJ. Bruce Fields gss_mech_get(source->cr_gss_mech); 231803a4e1f6SJ. Bruce Fields return 0; 23191da177e4SLinus Torvalds } 23201da177e4SLinus Torvalds 2321ef17af2aSRasmus Villemoes static int 2322ac55fdc4SJeff Layton compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) 2323ac55fdc4SJeff Layton { 2324ef17af2aSRasmus Villemoes if (o1->len < o2->len) 2325ef17af2aSRasmus Villemoes return -1; 2326ef17af2aSRasmus Villemoes if (o1->len > o2->len) 2327ef17af2aSRasmus Villemoes return 1; 2328ef17af2aSRasmus Villemoes return memcmp(o1->data, o2->data, o1->len); 2329ac55fdc4SJeff Layton } 2330ac55fdc4SJeff Layton 23311da177e4SLinus Torvalds static int 2332599e0a22SJ. Bruce Fields same_verf(nfs4_verifier *v1, nfs4_verifier *v2) 2333599e0a22SJ. Bruce Fields { 2334599e0a22SJ. Bruce Fields return 0 == memcmp(v1->data, v2->data, sizeof(v1->data)); 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds 23371da177e4SLinus Torvalds static int 2338599e0a22SJ. Bruce Fields same_clid(clientid_t *cl1, clientid_t *cl2) 2339599e0a22SJ. Bruce Fields { 2340599e0a22SJ. Bruce Fields return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); 23411da177e4SLinus Torvalds } 23421da177e4SLinus Torvalds 23438fbba96eSJ. Bruce Fields static bool groups_equal(struct group_info *g1, struct group_info *g2) 23448fbba96eSJ. Bruce Fields { 23458fbba96eSJ. Bruce Fields int i; 23468fbba96eSJ. Bruce Fields 23478fbba96eSJ. Bruce Fields if (g1->ngroups != g2->ngroups) 23488fbba96eSJ. Bruce Fields return false; 23498fbba96eSJ. Bruce Fields for (i=0; i<g1->ngroups; i++) 235081243eacSAlexey Dobriyan if (!gid_eq(g1->gid[i], g2->gid[i])) 23518fbba96eSJ. Bruce Fields return false; 23528fbba96eSJ. Bruce Fields return true; 23538fbba96eSJ. Bruce Fields } 23548fbba96eSJ. Bruce Fields 235568eb3508SJ. Bruce Fields /* 235668eb3508SJ. Bruce Fields * RFC 3530 language requires clid_inuse be returned when the 235768eb3508SJ. Bruce Fields * "principal" associated with a requests differs from that previously 235868eb3508SJ. Bruce Fields * used. We use uid, gid's, and gss principal string as our best 235968eb3508SJ. Bruce Fields * approximation. We also don't want to allow non-gss use of a client 236068eb3508SJ. Bruce Fields * established using gss: in theory cr_principal should catch that 236168eb3508SJ. Bruce Fields * change, but in practice cr_principal can be null even in the gss case 236268eb3508SJ. Bruce Fields * since gssd doesn't always pass down a principal string. 236368eb3508SJ. Bruce Fields */ 236468eb3508SJ. Bruce Fields static bool is_gss_cred(struct svc_cred *cr) 236568eb3508SJ. Bruce Fields { 236668eb3508SJ. Bruce Fields /* Is cr_flavor one of the gss "pseudoflavors"?: */ 236768eb3508SJ. Bruce Fields return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); 236868eb3508SJ. Bruce Fields } 236968eb3508SJ. Bruce Fields 237068eb3508SJ. Bruce Fields 23715559b50aSVivek Trivedi static bool 2372599e0a22SJ. Bruce Fields same_creds(struct svc_cred *cr1, struct svc_cred *cr2) 2373599e0a22SJ. Bruce Fields { 237468eb3508SJ. Bruce Fields if ((is_gss_cred(cr1) != is_gss_cred(cr2)) 23756fab8779SEric W. Biederman || (!uid_eq(cr1->cr_uid, cr2->cr_uid)) 23766fab8779SEric W. Biederman || (!gid_eq(cr1->cr_gid, cr2->cr_gid)) 23778fbba96eSJ. Bruce Fields || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) 23788fbba96eSJ. Bruce Fields return false; 23799abdda5dSChuck Lever /* XXX: check that cr_targ_princ fields match ? */ 23808fbba96eSJ. Bruce Fields if (cr1->cr_principal == cr2->cr_principal) 23818fbba96eSJ. Bruce Fields return true; 23828fbba96eSJ. Bruce Fields if (!cr1->cr_principal || !cr2->cr_principal) 23838fbba96eSJ. Bruce Fields return false; 23845559b50aSVivek Trivedi return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); 23851da177e4SLinus Torvalds } 23861da177e4SLinus Torvalds 238757266a6eSJ. Bruce Fields static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp) 238857266a6eSJ. Bruce Fields { 238957266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 239057266a6eSJ. Bruce Fields u32 service; 239157266a6eSJ. Bruce Fields 2392c4720591SJ. Bruce Fields if (!cr->cr_gss_mech) 2393c4720591SJ. Bruce Fields return false; 239457266a6eSJ. Bruce Fields service = gss_pseudoflavor_to_service(cr->cr_gss_mech, cr->cr_flavor); 239557266a6eSJ. Bruce Fields return service == RPC_GSS_SVC_INTEGRITY || 239657266a6eSJ. Bruce Fields service == RPC_GSS_SVC_PRIVACY; 239757266a6eSJ. Bruce Fields } 239857266a6eSJ. Bruce Fields 2399dedeb13fSAndrew Elble bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp) 240057266a6eSJ. Bruce Fields { 240157266a6eSJ. Bruce Fields struct svc_cred *cr = &rqstp->rq_cred; 240257266a6eSJ. Bruce Fields 240357266a6eSJ. Bruce Fields if (!cl->cl_mach_cred) 240457266a6eSJ. Bruce Fields return true; 240557266a6eSJ. Bruce Fields if (cl->cl_cred.cr_gss_mech != cr->cr_gss_mech) 240657266a6eSJ. Bruce Fields return false; 240757266a6eSJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) 240857266a6eSJ. Bruce Fields return false; 2409414ca017SJ. Bruce Fields if (cl->cl_cred.cr_raw_principal) 2410414ca017SJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_raw_principal, 2411414ca017SJ. Bruce Fields cr->cr_raw_principal); 241257266a6eSJ. Bruce Fields if (!cr->cr_principal) 241357266a6eSJ. Bruce Fields return false; 241457266a6eSJ. Bruce Fields return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal); 241557266a6eSJ. Bruce Fields } 241657266a6eSJ. Bruce Fields 2417294ac32eSJeff Layton static void gen_confirm(struct nfs4_client *clp, struct nfsd_net *nn) 2418deda2faaSJ. Bruce Fields { 2419ab4684d1SChuck Lever __be32 verf[2]; 24201da177e4SLinus Torvalds 2421f419992cSJeff Layton /* 2422f419992cSJeff Layton * This is opaque to client, so no need to byte-swap. Use 2423f419992cSJeff Layton * __force to keep sparse happy 2424f419992cSJeff Layton */ 24259104ae49SArnd Bergmann verf[0] = (__force __be32)(u32)ktime_get_real_seconds(); 242619311aa8SKinglong Mee verf[1] = (__force __be32)nn->clverifier_counter++; 2427ab4684d1SChuck Lever memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); 24281da177e4SLinus Torvalds } 24291da177e4SLinus Torvalds 2430294ac32eSJeff Layton static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) 2431294ac32eSJeff Layton { 24329cc76801SArnd Bergmann clp->cl_clientid.cl_boot = (u32)nn->boot_time; 2433294ac32eSJeff Layton clp->cl_clientid.cl_id = nn->clientid_counter++; 2434294ac32eSJeff Layton gen_confirm(clp, nn); 2435294ac32eSJeff Layton } 2436294ac32eSJeff Layton 24374770d722SJeff Layton static struct nfs4_stid * 24384770d722SJeff Layton find_stateid_locked(struct nfs4_client *cl, stateid_t *t) 24394581d140SJ. Bruce Fields { 24403abdb607SJ. Bruce Fields struct nfs4_stid *ret; 24413abdb607SJ. Bruce Fields 24423abdb607SJ. Bruce Fields ret = idr_find(&cl->cl_stateids, t->si_opaque.so_id); 24433abdb607SJ. Bruce Fields if (!ret || !ret->sc_type) 24443abdb607SJ. Bruce Fields return NULL; 24453abdb607SJ. Bruce Fields return ret; 24464581d140SJ. Bruce Fields } 24474d71ab87SJ. Bruce Fields 24484770d722SJeff Layton static struct nfs4_stid * 24494770d722SJeff Layton find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) 2450f459e453SJ. Bruce Fields { 2451f459e453SJ. Bruce Fields struct nfs4_stid *s; 2452f459e453SJ. Bruce Fields 24534770d722SJeff Layton spin_lock(&cl->cl_lock); 24544770d722SJeff Layton s = find_stateid_locked(cl, t); 24552d3f9668STrond Myklebust if (s != NULL) { 24562d3f9668STrond Myklebust if (typemask & s->sc_type) 2457a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 24582d3f9668STrond Myklebust else 24594770d722SJeff Layton s = NULL; 24602d3f9668STrond Myklebust } 24614770d722SJeff Layton spin_unlock(&cl->cl_lock); 24624d71ab87SJ. Bruce Fields return s; 24634581d140SJ. Bruce Fields } 24644581d140SJ. Bruce Fields 2465a204f25eSJ. Bruce Fields static struct nfs4_client *get_nfsdfs_clp(struct inode *inode) 2466a204f25eSJ. Bruce Fields { 2467a204f25eSJ. Bruce Fields struct nfsdfs_client *nc; 2468a204f25eSJ. Bruce Fields nc = get_nfsdfs_client(inode); 2469a204f25eSJ. Bruce Fields if (!nc) 2470a204f25eSJ. Bruce Fields return NULL; 2471a204f25eSJ. Bruce Fields return container_of(nc, struct nfs4_client, cl_nfsdfs); 2472a204f25eSJ. Bruce Fields } 2473a204f25eSJ. Bruce Fields 2474169319f1SJ. Bruce Fields static void seq_quote_mem(struct seq_file *m, char *data, int len) 2475169319f1SJ. Bruce Fields { 2476169319f1SJ. Bruce Fields seq_printf(m, "\""); 2477c0546391SAndy Shevchenko seq_escape_mem(m, data, len, ESCAPE_HEX | ESCAPE_NAP | ESCAPE_APPEND, "\"\\"); 2478169319f1SJ. Bruce Fields seq_printf(m, "\""); 2479169319f1SJ. Bruce Fields } 2480169319f1SJ. Bruce Fields 24813518c866SDave Wysochanski static const char *cb_state2str(int state) 24823518c866SDave Wysochanski { 24833518c866SDave Wysochanski switch (state) { 24843518c866SDave Wysochanski case NFSD4_CB_UP: 24853518c866SDave Wysochanski return "UP"; 24863518c866SDave Wysochanski case NFSD4_CB_UNKNOWN: 24873518c866SDave Wysochanski return "UNKNOWN"; 24883518c866SDave Wysochanski case NFSD4_CB_DOWN: 24893518c866SDave Wysochanski return "DOWN"; 24903518c866SDave Wysochanski case NFSD4_CB_FAULT: 24913518c866SDave Wysochanski return "FAULT"; 24923518c866SDave Wysochanski } 24933518c866SDave Wysochanski return "UNDEFINED"; 24943518c866SDave Wysochanski } 24953518c866SDave Wysochanski 249697ad4031SJ. Bruce Fields static int client_info_show(struct seq_file *m, void *v) 249797ad4031SJ. Bruce Fields { 24981d7f6b30SChenXiaoSong struct inode *inode = file_inode(m->file); 249997ad4031SJ. Bruce Fields struct nfs4_client *clp; 250097ad4031SJ. Bruce Fields u64 clid; 250197ad4031SJ. Bruce Fields 2502a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2503a204f25eSJ. Bruce Fields if (!clp) 250497ad4031SJ. Bruce Fields return -ENXIO; 250597ad4031SJ. Bruce Fields memcpy(&clid, &clp->cl_clientid, sizeof(clid)); 250697ad4031SJ. Bruce Fields seq_printf(m, "clientid: 0x%llx\n", clid); 2507169319f1SJ. Bruce Fields seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); 2508e9488d5aSDai Ngo 2509e9488d5aSDai Ngo if (clp->cl_state == NFSD4_COURTESY) 2510e9488d5aSDai Ngo seq_puts(m, "status: courtesy\n"); 2511e9488d5aSDai Ngo else if (clp->cl_state == NFSD4_EXPIRABLE) 2512e9488d5aSDai Ngo seq_puts(m, "status: expirable\n"); 2513e9488d5aSDai Ngo else if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) 2514472d155aSNeilBrown seq_puts(m, "status: confirmed\n"); 2515472d155aSNeilBrown else 2516472d155aSNeilBrown seq_puts(m, "status: unconfirmed\n"); 2517e9488d5aSDai Ngo seq_printf(m, "seconds from last renew: %lld\n", 2518e9488d5aSDai Ngo ktime_get_boottime_seconds() - clp->cl_time); 2519169319f1SJ. Bruce Fields seq_printf(m, "name: "); 2520169319f1SJ. Bruce Fields seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); 2521169319f1SJ. Bruce Fields seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); 252279123444SJ. Bruce Fields if (clp->cl_nii_domain.data) { 252379123444SJ. Bruce Fields seq_printf(m, "Implementation domain: "); 252479123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_domain.data, 252579123444SJ. Bruce Fields clp->cl_nii_domain.len); 252679123444SJ. Bruce Fields seq_printf(m, "\nImplementation name: "); 252779123444SJ. Bruce Fields seq_quote_mem(m, clp->cl_nii_name.data, clp->cl_nii_name.len); 2528e29f4703SArnd Bergmann seq_printf(m, "\nImplementation time: [%lld, %ld]\n", 252979123444SJ. Bruce Fields clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); 253079123444SJ. Bruce Fields } 25313518c866SDave Wysochanski seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state)); 25323518c866SDave Wysochanski seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr); 253397ad4031SJ. Bruce Fields drop_client(clp); 253497ad4031SJ. Bruce Fields 253597ad4031SJ. Bruce Fields return 0; 253697ad4031SJ. Bruce Fields } 253797ad4031SJ. Bruce Fields 25381d7f6b30SChenXiaoSong DEFINE_SHOW_ATTRIBUTE(client_info); 253997ad4031SJ. Bruce Fields 254078599c42SJ. Bruce Fields static void *states_start(struct seq_file *s, loff_t *pos) 254178599c42SJ. Bruce Fields __acquires(&clp->cl_lock) 254278599c42SJ. Bruce Fields { 254378599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 254478599c42SJ. Bruce Fields unsigned long id = *pos; 254578599c42SJ. Bruce Fields void *ret; 254678599c42SJ. Bruce Fields 254778599c42SJ. Bruce Fields spin_lock(&clp->cl_lock); 254878599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 254978599c42SJ. Bruce Fields *pos = id; 255078599c42SJ. Bruce Fields return ret; 255178599c42SJ. Bruce Fields } 255278599c42SJ. Bruce Fields 255378599c42SJ. Bruce Fields static void *states_next(struct seq_file *s, void *v, loff_t *pos) 255478599c42SJ. Bruce Fields { 255578599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 255678599c42SJ. Bruce Fields unsigned long id = *pos; 255778599c42SJ. Bruce Fields void *ret; 255878599c42SJ. Bruce Fields 255978599c42SJ. Bruce Fields id = *pos; 256078599c42SJ. Bruce Fields id++; 256178599c42SJ. Bruce Fields ret = idr_get_next_ul(&clp->cl_stateids, &id); 256278599c42SJ. Bruce Fields *pos = id; 256378599c42SJ. Bruce Fields return ret; 256478599c42SJ. Bruce Fields } 256578599c42SJ. Bruce Fields 256678599c42SJ. Bruce Fields static void states_stop(struct seq_file *s, void *v) 256778599c42SJ. Bruce Fields __releases(&clp->cl_lock) 256878599c42SJ. Bruce Fields { 256978599c42SJ. Bruce Fields struct nfs4_client *clp = s->private; 257078599c42SJ. Bruce Fields 257178599c42SJ. Bruce Fields spin_unlock(&clp->cl_lock); 257278599c42SJ. Bruce Fields } 257378599c42SJ. Bruce Fields 2574580da465SAchilles Gaikwad static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f) 2575580da465SAchilles Gaikwad { 2576580da465SAchilles Gaikwad seq_printf(s, "filename: \"%pD2\"", f->nf_file); 2577580da465SAchilles Gaikwad } 2578580da465SAchilles Gaikwad 2579fd4f83fdSJeff Layton static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) 258078599c42SJ. Bruce Fields { 2581427f5f83SChuck Lever struct inode *inode = file_inode(f->nf_file); 258278599c42SJ. Bruce Fields 258378599c42SJ. Bruce Fields seq_printf(s, "superblock: \"%02x:%02x:%ld\"", 258478599c42SJ. Bruce Fields MAJOR(inode->i_sb->s_dev), 258578599c42SJ. Bruce Fields MINOR(inode->i_sb->s_dev), 258678599c42SJ. Bruce Fields inode->i_ino); 258778599c42SJ. Bruce Fields } 258878599c42SJ. Bruce Fields 258978599c42SJ. Bruce Fields static void nfs4_show_owner(struct seq_file *s, struct nfs4_stateowner *oo) 259078599c42SJ. Bruce Fields { 259178599c42SJ. Bruce Fields seq_printf(s, "owner: "); 259278599c42SJ. Bruce Fields seq_quote_mem(s, oo->so_owner.data, oo->so_owner.len); 259378599c42SJ. Bruce Fields } 259478599c42SJ. Bruce Fields 2595ace7ade4SJ. Bruce Fields static void nfs4_show_stateid(struct seq_file *s, stateid_t *stid) 2596ace7ade4SJ. Bruce Fields { 2597ee590d25SJ. Bruce Fields seq_printf(s, "0x%.8x", stid->si_generation); 2598ee590d25SJ. Bruce Fields seq_printf(s, "%12phN", &stid->si_opaque); 2599ace7ade4SJ. Bruce Fields } 2600ace7ade4SJ. Bruce Fields 260178599c42SJ. Bruce Fields static int nfs4_show_open(struct seq_file *s, struct nfs4_stid *st) 260278599c42SJ. Bruce Fields { 260378599c42SJ. Bruce Fields struct nfs4_ol_stateid *ols; 260478599c42SJ. Bruce Fields struct nfs4_file *nf; 2605fd4f83fdSJeff Layton struct nfsd_file *file; 260678599c42SJ. Bruce Fields struct nfs4_stateowner *oo; 260778599c42SJ. Bruce Fields unsigned int access, deny; 260878599c42SJ. Bruce Fields 260978599c42SJ. Bruce Fields if (st->sc_type != NFS4_OPEN_STID && st->sc_type != NFS4_LOCK_STID) 261078599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 261178599c42SJ. Bruce Fields ols = openlockstateid(st); 261278599c42SJ. Bruce Fields oo = ols->st_stateowner; 261378599c42SJ. Bruce Fields nf = st->sc_file; 2614e0aa6510SJeff Layton 2615e0aa6510SJeff Layton spin_lock(&nf->fi_lock); 2616e0aa6510SJeff Layton file = find_any_file_locked(nf); 26179affa435SJ. Bruce Fields if (!file) 2618e0aa6510SJeff Layton goto out; 261978599c42SJ. Bruce Fields 2620ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2621ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2622ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: open, "); 262378599c42SJ. Bruce Fields 262478599c42SJ. Bruce Fields access = bmap_to_share_mode(ols->st_access_bmap); 262578599c42SJ. Bruce Fields deny = bmap_to_share_mode(ols->st_deny_bmap); 262678599c42SJ. Bruce Fields 2627c4b77edbSJ. Bruce Fields seq_printf(s, "access: %s%s, ", 262878599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_READ ? "r" : "-", 262978599c42SJ. Bruce Fields access & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 2630c4b77edbSJ. Bruce Fields seq_printf(s, "deny: %s%s, ", 263178599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_READ ? "r" : "-", 263278599c42SJ. Bruce Fields deny & NFS4_SHARE_ACCESS_WRITE ? "w" : "-"); 263378599c42SJ. Bruce Fields 263478599c42SJ. Bruce Fields nfs4_show_superblock(s, file); 263578599c42SJ. Bruce Fields seq_printf(s, ", "); 2636580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2637580da465SAchilles Gaikwad seq_printf(s, ", "); 263878599c42SJ. Bruce Fields nfs4_show_owner(s, oo); 263978599c42SJ. Bruce Fields seq_printf(s, " }\n"); 2640e0aa6510SJeff Layton out: 2641e0aa6510SJeff Layton spin_unlock(&nf->fi_lock); 264278599c42SJ. Bruce Fields return 0; 264378599c42SJ. Bruce Fields } 264478599c42SJ. Bruce Fields 264516d36e09SJ. Bruce Fields static int nfs4_show_lock(struct seq_file *s, struct nfs4_stid *st) 264616d36e09SJ. Bruce Fields { 264716d36e09SJ. Bruce Fields struct nfs4_ol_stateid *ols; 264816d36e09SJ. Bruce Fields struct nfs4_file *nf; 2649fd4f83fdSJeff Layton struct nfsd_file *file; 265016d36e09SJ. Bruce Fields struct nfs4_stateowner *oo; 265116d36e09SJ. Bruce Fields 265216d36e09SJ. Bruce Fields ols = openlockstateid(st); 265316d36e09SJ. Bruce Fields oo = ols->st_stateowner; 265416d36e09SJ. Bruce Fields nf = st->sc_file; 2655e0aa6510SJeff Layton spin_lock(&nf->fi_lock); 2656e0aa6510SJeff Layton file = find_any_file_locked(nf); 26579affa435SJ. Bruce Fields if (!file) 2658e0aa6510SJeff Layton goto out; 265916d36e09SJ. Bruce Fields 2660ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2661ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2662ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: lock, "); 266316d36e09SJ. Bruce Fields 266416d36e09SJ. Bruce Fields /* 266516d36e09SJ. Bruce Fields * Note: a lock stateid isn't really the same thing as a lock, 266616d36e09SJ. Bruce Fields * it's the locking state held by one owner on a file, and there 266716d36e09SJ. Bruce Fields * may be multiple (or no) lock ranges associated with it. 266816d36e09SJ. Bruce Fields * (Same for the matter is true of open stateids.) 266916d36e09SJ. Bruce Fields */ 267016d36e09SJ. Bruce Fields 267116d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 267216d36e09SJ. Bruce Fields /* XXX: open stateid? */ 267316d36e09SJ. Bruce Fields seq_printf(s, ", "); 2674580da465SAchilles Gaikwad nfs4_show_fname(s, file); 2675580da465SAchilles Gaikwad seq_printf(s, ", "); 267616d36e09SJ. Bruce Fields nfs4_show_owner(s, oo); 267716d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2678e0aa6510SJeff Layton out: 2679e0aa6510SJeff Layton spin_unlock(&nf->fi_lock); 268016d36e09SJ. Bruce Fields return 0; 268116d36e09SJ. Bruce Fields } 268216d36e09SJ. Bruce Fields 268316d36e09SJ. Bruce Fields static int nfs4_show_deleg(struct seq_file *s, struct nfs4_stid *st) 268416d36e09SJ. Bruce Fields { 268516d36e09SJ. Bruce Fields struct nfs4_delegation *ds; 268616d36e09SJ. Bruce Fields struct nfs4_file *nf; 2687eb82dd39SJeff Layton struct nfsd_file *file; 268816d36e09SJ. Bruce Fields 268916d36e09SJ. Bruce Fields ds = delegstateid(st); 269016d36e09SJ. Bruce Fields nf = st->sc_file; 2691e0aa6510SJeff Layton spin_lock(&nf->fi_lock); 269245ba66ccSJeff Layton file = nf->fi_deleg_file; 26939affa435SJ. Bruce Fields if (!file) 2694e0aa6510SJeff Layton goto out; 269516d36e09SJ. Bruce Fields 2696ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2697ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2698ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: deleg, "); 269916d36e09SJ. Bruce Fields 270016d36e09SJ. Bruce Fields /* Kinda dead code as long as we only support read delegs: */ 270116d36e09SJ. Bruce Fields seq_printf(s, "access: %s, ", 270216d36e09SJ. Bruce Fields ds->dl_type == NFS4_OPEN_DELEGATE_READ ? "r" : "w"); 270316d36e09SJ. Bruce Fields 270416d36e09SJ. Bruce Fields /* XXX: lease time, whether it's being recalled. */ 270516d36e09SJ. Bruce Fields 270616d36e09SJ. Bruce Fields nfs4_show_superblock(s, file); 2707580da465SAchilles Gaikwad seq_printf(s, ", "); 2708580da465SAchilles Gaikwad nfs4_show_fname(s, file); 270916d36e09SJ. Bruce Fields seq_printf(s, " }\n"); 2710e0aa6510SJeff Layton out: 2711e0aa6510SJeff Layton spin_unlock(&nf->fi_lock); 271216d36e09SJ. Bruce Fields return 0; 271316d36e09SJ. Bruce Fields } 271416d36e09SJ. Bruce Fields 27150c4b62b0SJ. Bruce Fields static int nfs4_show_layout(struct seq_file *s, struct nfs4_stid *st) 27160c4b62b0SJ. Bruce Fields { 27170c4b62b0SJ. Bruce Fields struct nfs4_layout_stateid *ls; 2718eb82dd39SJeff Layton struct nfsd_file *file; 27190c4b62b0SJ. Bruce Fields 27200c4b62b0SJ. Bruce Fields ls = container_of(st, struct nfs4_layout_stateid, ls_stid); 27210c4b62b0SJ. Bruce Fields file = ls->ls_file; 27220c4b62b0SJ. Bruce Fields 2723ace7ade4SJ. Bruce Fields seq_printf(s, "- "); 2724ace7ade4SJ. Bruce Fields nfs4_show_stateid(s, &st->sc_stateid); 2725ace7ade4SJ. Bruce Fields seq_printf(s, ": { type: layout, "); 27260c4b62b0SJ. Bruce Fields 27270c4b62b0SJ. Bruce Fields /* XXX: What else would be useful? */ 27280c4b62b0SJ. Bruce Fields 27290c4b62b0SJ. Bruce Fields nfs4_show_superblock(s, file); 2730580da465SAchilles Gaikwad seq_printf(s, ", "); 2731580da465SAchilles Gaikwad nfs4_show_fname(s, file); 27320c4b62b0SJ. Bruce Fields seq_printf(s, " }\n"); 27330c4b62b0SJ. Bruce Fields 27340c4b62b0SJ. Bruce Fields return 0; 27350c4b62b0SJ. Bruce Fields } 27360c4b62b0SJ. Bruce Fields 273778599c42SJ. Bruce Fields static int states_show(struct seq_file *s, void *v) 273878599c42SJ. Bruce Fields { 273978599c42SJ. Bruce Fields struct nfs4_stid *st = v; 274078599c42SJ. Bruce Fields 274178599c42SJ. Bruce Fields switch (st->sc_type) { 274278599c42SJ. Bruce Fields case NFS4_OPEN_STID: 274378599c42SJ. Bruce Fields return nfs4_show_open(s, st); 274416d36e09SJ. Bruce Fields case NFS4_LOCK_STID: 274516d36e09SJ. Bruce Fields return nfs4_show_lock(s, st); 274616d36e09SJ. Bruce Fields case NFS4_DELEG_STID: 274716d36e09SJ. Bruce Fields return nfs4_show_deleg(s, st); 27480c4b62b0SJ. Bruce Fields case NFS4_LAYOUT_STID: 27490c4b62b0SJ. Bruce Fields return nfs4_show_layout(s, st); 275078599c42SJ. Bruce Fields default: 275178599c42SJ. Bruce Fields return 0; /* XXX: or SEQ_SKIP? */ 275278599c42SJ. Bruce Fields } 275316d36e09SJ. Bruce Fields /* XXX: copy stateids? */ 275478599c42SJ. Bruce Fields } 275578599c42SJ. Bruce Fields 275678599c42SJ. Bruce Fields static struct seq_operations states_seq_ops = { 275778599c42SJ. Bruce Fields .start = states_start, 275878599c42SJ. Bruce Fields .next = states_next, 275978599c42SJ. Bruce Fields .stop = states_stop, 276078599c42SJ. Bruce Fields .show = states_show 276178599c42SJ. Bruce Fields }; 276278599c42SJ. Bruce Fields 276378599c42SJ. Bruce Fields static int client_states_open(struct inode *inode, struct file *file) 276478599c42SJ. Bruce Fields { 276578599c42SJ. Bruce Fields struct seq_file *s; 276678599c42SJ. Bruce Fields struct nfs4_client *clp; 276778599c42SJ. Bruce Fields int ret; 276878599c42SJ. Bruce Fields 2769a204f25eSJ. Bruce Fields clp = get_nfsdfs_clp(inode); 2770a204f25eSJ. Bruce Fields if (!clp) 277178599c42SJ. Bruce Fields return -ENXIO; 277278599c42SJ. Bruce Fields 277378599c42SJ. Bruce Fields ret = seq_open(file, &states_seq_ops); 277478599c42SJ. Bruce Fields if (ret) 277578599c42SJ. Bruce Fields return ret; 277678599c42SJ. Bruce Fields s = file->private_data; 277778599c42SJ. Bruce Fields s->private = clp; 277878599c42SJ. Bruce Fields return 0; 277978599c42SJ. Bruce Fields } 278078599c42SJ. Bruce Fields 278178599c42SJ. Bruce Fields static int client_opens_release(struct inode *inode, struct file *file) 278278599c42SJ. Bruce Fields { 278378599c42SJ. Bruce Fields struct seq_file *m = file->private_data; 278478599c42SJ. Bruce Fields struct nfs4_client *clp = m->private; 278578599c42SJ. Bruce Fields 278678599c42SJ. Bruce Fields /* XXX: alternatively, we could get/drop in seq start/stop */ 278778599c42SJ. Bruce Fields drop_client(clp); 278878599c42SJ. Bruce Fields return 0; 278978599c42SJ. Bruce Fields } 279078599c42SJ. Bruce Fields 279178599c42SJ. Bruce Fields static const struct file_operations client_states_fops = { 279278599c42SJ. Bruce Fields .open = client_states_open, 279378599c42SJ. Bruce Fields .read = seq_read, 279478599c42SJ. Bruce Fields .llseek = seq_lseek, 279578599c42SJ. Bruce Fields .release = client_opens_release, 279678599c42SJ. Bruce Fields }; 279778599c42SJ. Bruce Fields 279889c905beSJ. Bruce Fields /* 279989c905beSJ. Bruce Fields * Normally we refuse to destroy clients that are in use, but here the 280089c905beSJ. Bruce Fields * administrator is telling us to just do it. We also want to wait 280189c905beSJ. Bruce Fields * so the caller has a guarantee that the client's locks are gone by 280289c905beSJ. Bruce Fields * the time the write returns: 280389c905beSJ. Bruce Fields */ 2804297e57a2SYueHaibing static void force_expire_client(struct nfs4_client *clp) 280589c905beSJ. Bruce Fields { 280689c905beSJ. Bruce Fields struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 280789c905beSJ. Bruce Fields bool already_expired; 280889c905beSJ. Bruce Fields 28092958d2eeSChuck Lever trace_nfsd_clid_admin_expired(&clp->cl_clientid); 28102958d2eeSChuck Lever 2811f7104cc1SJ. Bruce Fields spin_lock(&nn->client_lock); 281289c905beSJ. Bruce Fields clp->cl_time = 0; 2813f7104cc1SJ. Bruce Fields spin_unlock(&nn->client_lock); 281489c905beSJ. Bruce Fields 281589c905beSJ. Bruce Fields wait_event(expiry_wq, atomic_read(&clp->cl_rpc_users) == 0); 281689c905beSJ. Bruce Fields spin_lock(&nn->client_lock); 281789c905beSJ. Bruce Fields already_expired = list_empty(&clp->cl_lru); 281889c905beSJ. Bruce Fields if (!already_expired) 281989c905beSJ. Bruce Fields unhash_client_locked(clp); 282089c905beSJ. Bruce Fields spin_unlock(&nn->client_lock); 282189c905beSJ. Bruce Fields 282289c905beSJ. Bruce Fields if (!already_expired) 282389c905beSJ. Bruce Fields expire_client(clp); 282489c905beSJ. Bruce Fields else 282589c905beSJ. Bruce Fields wait_event(expiry_wq, clp->cl_nfsd_dentry == NULL); 282689c905beSJ. Bruce Fields } 282789c905beSJ. Bruce Fields 282889c905beSJ. Bruce Fields static ssize_t client_ctl_write(struct file *file, const char __user *buf, 282989c905beSJ. Bruce Fields size_t size, loff_t *pos) 283089c905beSJ. Bruce Fields { 283189c905beSJ. Bruce Fields char *data; 283289c905beSJ. Bruce Fields struct nfs4_client *clp; 283389c905beSJ. Bruce Fields 283489c905beSJ. Bruce Fields data = simple_transaction_get(file, buf, size); 283589c905beSJ. Bruce Fields if (IS_ERR(data)) 283689c905beSJ. Bruce Fields return PTR_ERR(data); 283789c905beSJ. Bruce Fields if (size != 7 || 0 != memcmp(data, "expire\n", 7)) 283889c905beSJ. Bruce Fields return -EINVAL; 283989c905beSJ. Bruce Fields clp = get_nfsdfs_clp(file_inode(file)); 284089c905beSJ. Bruce Fields if (!clp) 284189c905beSJ. Bruce Fields return -ENXIO; 284289c905beSJ. Bruce Fields force_expire_client(clp); 284389c905beSJ. Bruce Fields drop_client(clp); 284489c905beSJ. Bruce Fields return 7; 284589c905beSJ. Bruce Fields } 284689c905beSJ. Bruce Fields 284789c905beSJ. Bruce Fields static const struct file_operations client_ctl_fops = { 284889c905beSJ. Bruce Fields .write = client_ctl_write, 284989c905beSJ. Bruce Fields .release = simple_transaction_release, 285089c905beSJ. Bruce Fields }; 285189c905beSJ. Bruce Fields 285297ad4031SJ. Bruce Fields static const struct tree_descr client_files[] = { 285397ad4031SJ. Bruce Fields [0] = {"info", &client_info_fops, S_IRUSR}, 285478599c42SJ. Bruce Fields [1] = {"states", &client_states_fops, S_IRUSR}, 28556cbfad5fSPetr Vorel [2] = {"ctl", &client_ctl_fops, S_IWUSR}, 285678599c42SJ. Bruce Fields [3] = {""}, 285797ad4031SJ. Bruce Fields }; 285897ad4031SJ. Bruce Fields 285944df6f43SDai Ngo static int 286044df6f43SDai Ngo nfsd4_cb_recall_any_done(struct nfsd4_callback *cb, 286144df6f43SDai Ngo struct rpc_task *task) 286244df6f43SDai Ngo { 2863638593beSDai Ngo trace_nfsd_cb_recall_any_done(cb, task); 286444df6f43SDai Ngo switch (task->tk_status) { 286544df6f43SDai Ngo case -NFS4ERR_DELAY: 286644df6f43SDai Ngo rpc_delay(task, 2 * HZ); 286744df6f43SDai Ngo return 0; 286844df6f43SDai Ngo default: 286944df6f43SDai Ngo return 1; 287044df6f43SDai Ngo } 287144df6f43SDai Ngo } 287244df6f43SDai Ngo 287344df6f43SDai Ngo static void 287444df6f43SDai Ngo nfsd4_cb_recall_any_release(struct nfsd4_callback *cb) 287544df6f43SDai Ngo { 287644df6f43SDai Ngo struct nfs4_client *clp = cb->cb_clp; 287744df6f43SDai Ngo struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 287844df6f43SDai Ngo 287944df6f43SDai Ngo spin_lock(&nn->client_lock); 288044df6f43SDai Ngo clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags); 288144df6f43SDai Ngo put_client_renew_locked(clp); 288244df6f43SDai Ngo spin_unlock(&nn->client_lock); 288344df6f43SDai Ngo } 288444df6f43SDai Ngo 288544df6f43SDai Ngo static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = { 288644df6f43SDai Ngo .done = nfsd4_cb_recall_any_done, 288744df6f43SDai Ngo .release = nfsd4_cb_recall_any_release, 288844df6f43SDai Ngo }; 288944df6f43SDai Ngo 28902216d449SJeff Layton static struct nfs4_client *create_client(struct xdr_netobj name, 2891b09333c4SRicardo Labiaga struct svc_rqst *rqstp, nfs4_verifier *verf) 2892b09333c4SRicardo Labiaga { 2893b09333c4SRicardo Labiaga struct nfs4_client *clp; 2894b09333c4SRicardo Labiaga struct sockaddr *sa = svc_addr(rqstp); 289503a4e1f6SJ. Bruce Fields int ret; 2896c212cecfSStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 2897e8a79fb1SJ. Bruce Fields struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2898472d155aSNeilBrown struct dentry *dentries[ARRAY_SIZE(client_files)]; 2899b09333c4SRicardo Labiaga 29000926c395SDai Ngo clp = alloc_client(name, nn); 2901b09333c4SRicardo Labiaga if (clp == NULL) 2902b09333c4SRicardo Labiaga return NULL; 2903b09333c4SRicardo Labiaga 290403a4e1f6SJ. Bruce Fields ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); 290503a4e1f6SJ. Bruce Fields if (ret) { 2906b09333c4SRicardo Labiaga free_client(clp); 2907b09333c4SRicardo Labiaga return NULL; 2908b09333c4SRicardo Labiaga } 2909e8a79fb1SJ. Bruce Fields gen_clid(clp, nn); 2910e8a79fb1SJ. Bruce Fields kref_init(&clp->cl_nfsdfs.cl_ref); 29110162ac2bSChristoph Hellwig nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); 291220b7d86fSArnd Bergmann clp->cl_time = ktime_get_boottime_seconds(); 2913b09333c4SRicardo Labiaga clear_bit(0, &clp->cl_cb_slot_busy); 2914b09333c4SRicardo Labiaga copy_verf(clp, verf); 29153bade247SJ. Bruce Fields memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); 2916edd76786SJ. Bruce Fields clp->cl_cb_session = NULL; 2917c212cecfSStanislav Kinsbursky clp->net = net; 2918472d155aSNeilBrown clp->cl_nfsd_dentry = nfsd_client_mkdir( 2919472d155aSNeilBrown nn, &clp->cl_nfsdfs, 292097ad4031SJ. Bruce Fields clp->cl_clientid.cl_id - nn->clientid_base, 2921472d155aSNeilBrown client_files, dentries); 2922472d155aSNeilBrown clp->cl_nfsd_info_dentry = dentries[0]; 2923e8a79fb1SJ. Bruce Fields if (!clp->cl_nfsd_dentry) { 2924e8a79fb1SJ. Bruce Fields free_client(clp); 2925e8a79fb1SJ. Bruce Fields return NULL; 2926e8a79fb1SJ. Bruce Fields } 292744df6f43SDai Ngo clp->cl_ra = kzalloc(sizeof(*clp->cl_ra), GFP_KERNEL); 292844df6f43SDai Ngo if (!clp->cl_ra) { 292944df6f43SDai Ngo free_client(clp); 293044df6f43SDai Ngo return NULL; 293144df6f43SDai Ngo } 293244df6f43SDai Ngo clp->cl_ra_time = 0; 293344df6f43SDai Ngo nfsd4_init_cb(&clp->cl_ra->ra_cb, clp, &nfsd4_cb_recall_any_ops, 293444df6f43SDai Ngo NFSPROC4_CLNT_CB_RECALL_ANY); 2935b09333c4SRicardo Labiaga return clp; 2936b09333c4SRicardo Labiaga } 2937b09333c4SRicardo Labiaga 2938fd39ca9aSNeilBrown static void 2939ac55fdc4SJeff Layton add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) 2940ac55fdc4SJeff Layton { 2941ac55fdc4SJeff Layton struct rb_node **new = &(root->rb_node), *parent = NULL; 2942ac55fdc4SJeff Layton struct nfs4_client *clp; 2943ac55fdc4SJeff Layton 2944ac55fdc4SJeff Layton while (*new) { 2945ac55fdc4SJeff Layton clp = rb_entry(*new, struct nfs4_client, cl_namenode); 2946ac55fdc4SJeff Layton parent = *new; 2947ac55fdc4SJeff Layton 2948ac55fdc4SJeff Layton if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) 2949ac55fdc4SJeff Layton new = &((*new)->rb_left); 2950ac55fdc4SJeff Layton else 2951ac55fdc4SJeff Layton new = &((*new)->rb_right); 2952ac55fdc4SJeff Layton } 2953ac55fdc4SJeff Layton 2954ac55fdc4SJeff Layton rb_link_node(&new_clp->cl_namenode, parent, new); 2955ac55fdc4SJeff Layton rb_insert_color(&new_clp->cl_namenode, root); 2956ac55fdc4SJeff Layton } 2957ac55fdc4SJeff Layton 2958ac55fdc4SJeff Layton static struct nfs4_client * 2959ac55fdc4SJeff Layton find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) 2960ac55fdc4SJeff Layton { 2961ef17af2aSRasmus Villemoes int cmp; 2962ac55fdc4SJeff Layton struct rb_node *node = root->rb_node; 2963ac55fdc4SJeff Layton struct nfs4_client *clp; 2964ac55fdc4SJeff Layton 2965ac55fdc4SJeff Layton while (node) { 2966ac55fdc4SJeff Layton clp = rb_entry(node, struct nfs4_client, cl_namenode); 2967ac55fdc4SJeff Layton cmp = compare_blob(&clp->cl_name, name); 2968ac55fdc4SJeff Layton if (cmp > 0) 2969ac55fdc4SJeff Layton node = node->rb_left; 2970ac55fdc4SJeff Layton else if (cmp < 0) 2971ac55fdc4SJeff Layton node = node->rb_right; 2972ac55fdc4SJeff Layton else 2973ac55fdc4SJeff Layton return clp; 2974ac55fdc4SJeff Layton } 2975ac55fdc4SJeff Layton return NULL; 2976ac55fdc4SJeff Layton } 2977ac55fdc4SJeff Layton 2978ac55fdc4SJeff Layton static void 2979ac55fdc4SJeff Layton add_to_unconfirmed(struct nfs4_client *clp) 29801da177e4SLinus Torvalds { 29811da177e4SLinus Torvalds unsigned int idhashval; 29820a7ec377SStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 29831da177e4SLinus Torvalds 29840a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 29850a880a28STrond Myklebust 2986ac55fdc4SJeff Layton clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 2987a99454aaSStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->unconf_name_tree); 29881da177e4SLinus Torvalds idhashval = clientid_hashval(clp->cl_clientid.cl_id); 29890a7ec377SStanislav Kinsbursky list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); 29903dbacee6STrond Myklebust renew_client_locked(clp); 29911da177e4SLinus Torvalds } 29921da177e4SLinus Torvalds 2993fd39ca9aSNeilBrown static void 29941da177e4SLinus Torvalds move_to_confirmed(struct nfs4_client *clp) 29951da177e4SLinus Torvalds { 29961da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); 29978daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 29981da177e4SLinus Torvalds 29990a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 30000a880a28STrond Myklebust 30018daae4dcSStanislav Kinsbursky list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); 3002a99454aaSStanislav Kinsbursky rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); 3003382a62e7SStanislav Kinsbursky add_clp_to_name_tree(clp, &nn->conf_name_tree); 3004934bd07fSJ. Bruce Fields set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); 30057e3b32acSChuck Lever trace_nfsd_clid_confirmed(&clp->cl_clientid); 30063dbacee6STrond Myklebust renew_client_locked(clp); 30071da177e4SLinus Torvalds } 30081da177e4SLinus Torvalds 30091da177e4SLinus Torvalds static struct nfs4_client * 3010bfa85e83SJ. Bruce Fields find_client_in_id_table(struct list_head *tbl, clientid_t *clid, bool sessions) 30111da177e4SLinus Torvalds { 30121da177e4SLinus Torvalds struct nfs4_client *clp; 30131da177e4SLinus Torvalds unsigned int idhashval = clientid_hashval(clid->cl_id); 30141da177e4SLinus Torvalds 3015bfa85e83SJ. Bruce Fields list_for_each_entry(clp, &tbl[idhashval], cl_idhash) { 3016a50d2ad1SJ. Bruce Fields if (same_clid(&clp->cl_clientid, clid)) { 3017d15c077eSJ. Bruce Fields if ((bool)clp->cl_minorversion != sessions) 3018d15c077eSJ. Bruce Fields return NULL; 30193dbacee6STrond Myklebust renew_client_locked(clp); 30201da177e4SLinus Torvalds return clp; 30211da177e4SLinus Torvalds } 3022a50d2ad1SJ. Bruce Fields } 30231da177e4SLinus Torvalds return NULL; 30241da177e4SLinus Torvalds } 30251da177e4SLinus Torvalds 30261da177e4SLinus Torvalds static struct nfs4_client * 3027bfa85e83SJ. Bruce Fields find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 3028bfa85e83SJ. Bruce Fields { 3029bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->conf_id_hashtbl; 3030bfa85e83SJ. Bruce Fields 30310a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3032bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 3033bfa85e83SJ. Bruce Fields } 3034bfa85e83SJ. Bruce Fields 3035bfa85e83SJ. Bruce Fields static struct nfs4_client * 30360a7ec377SStanislav Kinsbursky find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) 30371da177e4SLinus Torvalds { 3038bfa85e83SJ. Bruce Fields struct list_head *tbl = nn->unconf_id_hashtbl; 30391da177e4SLinus Torvalds 30400a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3041bfa85e83SJ. Bruce Fields return find_client_in_id_table(tbl, clid, sessions); 30421da177e4SLinus Torvalds } 30431da177e4SLinus Torvalds 30446e5f15c9SJ. Bruce Fields static bool clp_used_exchangeid(struct nfs4_client *clp) 3045a1bcecd2SAndy Adamson { 30466e5f15c9SJ. Bruce Fields return clp->cl_exchange_flags != 0; 3047a1bcecd2SAndy Adamson } 3048a1bcecd2SAndy Adamson 304928ce6054SNeilBrown static struct nfs4_client * 3050382a62e7SStanislav Kinsbursky find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 305128ce6054SNeilBrown { 30520a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3053382a62e7SStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->conf_name_tree); 305428ce6054SNeilBrown } 305528ce6054SNeilBrown 305628ce6054SNeilBrown static struct nfs4_client * 3057a99454aaSStanislav Kinsbursky find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) 305828ce6054SNeilBrown { 30590a880a28STrond Myklebust lockdep_assert_held(&nn->client_lock); 3060a99454aaSStanislav Kinsbursky return find_clp_in_name_tree(name, &nn->unconf_name_tree); 306128ce6054SNeilBrown } 306228ce6054SNeilBrown 3063fd39ca9aSNeilBrown static void 30646f3d772fSTakuma Umeya gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp) 30651da177e4SLinus Torvalds { 306607263f1eSJ. Bruce Fields struct nfs4_cb_conn *conn = &clp->cl_cb_conn; 30676f3d772fSTakuma Umeya struct sockaddr *sa = svc_addr(rqstp); 30686f3d772fSTakuma Umeya u32 scopeid = rpc_get_scope_id(sa); 30697077ecbaSJeff Layton unsigned short expected_family; 30701da177e4SLinus Torvalds 30717077ecbaSJeff Layton /* Currently, we only support tcp and tcp6 for the callback channel */ 30727077ecbaSJeff Layton if (se->se_callback_netid_len == 3 && 30737077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp", 3)) 30747077ecbaSJeff Layton expected_family = AF_INET; 30757077ecbaSJeff Layton else if (se->se_callback_netid_len == 4 && 30767077ecbaSJeff Layton !memcmp(se->se_callback_netid_val, "tcp6", 4)) 30777077ecbaSJeff Layton expected_family = AF_INET6; 30787077ecbaSJeff Layton else 30791da177e4SLinus Torvalds goto out_err; 30801da177e4SLinus Torvalds 3081c212cecfSStanislav Kinsbursky conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, 3082aa9a4ec7SJeff Layton se->se_callback_addr_len, 308307263f1eSJ. Bruce Fields (struct sockaddr *)&conn->cb_addr, 308407263f1eSJ. Bruce Fields sizeof(conn->cb_addr)); 3085aa9a4ec7SJeff Layton 308607263f1eSJ. Bruce Fields if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family) 30871da177e4SLinus Torvalds goto out_err; 3088aa9a4ec7SJeff Layton 308907263f1eSJ. Bruce Fields if (conn->cb_addr.ss_family == AF_INET6) 309007263f1eSJ. Bruce Fields ((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid; 3091fbf4665fSJeff Layton 309207263f1eSJ. Bruce Fields conn->cb_prog = se->se_callback_prog; 309307263f1eSJ. Bruce Fields conn->cb_ident = se->se_callback_ident; 3094849a1cf1SMi Jinlong memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); 30951eace0d1SChuck Lever trace_nfsd_cb_args(clp, conn); 30961da177e4SLinus Torvalds return; 30971da177e4SLinus Torvalds out_err: 309807263f1eSJ. Bruce Fields conn->cb_addr.ss_family = AF_UNSPEC; 309907263f1eSJ. Bruce Fields conn->cb_addrlen = 0; 31001eace0d1SChuck Lever trace_nfsd_cb_nodelegs(clp); 31011da177e4SLinus Torvalds return; 31021da177e4SLinus Torvalds } 31031da177e4SLinus Torvalds 3104074fe897SAndy Adamson /* 3105067e1aceSJ. Bruce Fields * Cache a reply. nfsd4_check_resp_size() has bounded the cache size. 3106074fe897SAndy Adamson */ 3107b607664eSTrond Myklebust static void 3108074fe897SAndy Adamson nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) 3109074fe897SAndy Adamson { 3110bddfdbcdSChuck Lever struct xdr_buf *buf = resp->xdr->buf; 3111557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3112557ce264SAndy Adamson unsigned int base; 3113074fe897SAndy Adamson 3114557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 3115074fe897SAndy Adamson 3116085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INITIALIZED; 3117557ce264SAndy Adamson slot->sl_opcnt = resp->opcnt; 3118557ce264SAndy Adamson slot->sl_status = resp->cstate.status; 311953da6a53SJ. Bruce Fields free_svc_cred(&slot->sl_cred); 312053da6a53SJ. Bruce Fields copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred); 3121bf864a31SAndy Adamson 3122085def3aSJ. Bruce Fields if (!nfsd4_cache_this(resp)) { 3123085def3aSJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHED; 3124bf864a31SAndy Adamson return; 3125bf864a31SAndy Adamson } 3126085def3aSJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHED; 3127085def3aSJ. Bruce Fields 3128f5236013SJ. Bruce Fields base = resp->cstate.data_offset; 3129f5236013SJ. Bruce Fields slot->sl_datalen = buf->len - base; 3130f5236013SJ. Bruce Fields if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen)) 3131d3f03403SDan Carpenter WARN(1, "%s: sessions DRC could not cache compound\n", 3132d3f03403SDan Carpenter __func__); 3133557ce264SAndy Adamson return; 3134074fe897SAndy Adamson } 3135074fe897SAndy Adamson 3136074fe897SAndy Adamson /* 3137abfabf8cSAndy Adamson * Encode the replay sequence operation from the slot values. 3138abfabf8cSAndy Adamson * If cachethis is FALSE encode the uncached rep error on the next 3139abfabf8cSAndy Adamson * operation which sets resp->p and increments resp->opcnt for 3140abfabf8cSAndy Adamson * nfs4svc_encode_compoundres. 3141abfabf8cSAndy Adamson * 3142074fe897SAndy Adamson */ 3143abfabf8cSAndy Adamson static __be32 3144abfabf8cSAndy Adamson nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, 3145abfabf8cSAndy Adamson struct nfsd4_compoundres *resp) 3146074fe897SAndy Adamson { 3147abfabf8cSAndy Adamson struct nfsd4_op *op; 3148abfabf8cSAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3149074fe897SAndy Adamson 3150abfabf8cSAndy Adamson /* Encode the replayed sequence operation */ 3151abfabf8cSAndy Adamson op = &args->ops[resp->opcnt - 1]; 3152abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 3153abfabf8cSAndy Adamson 3154085def3aSJ. Bruce Fields if (slot->sl_flags & NFSD4_SLOT_CACHED) 3155085def3aSJ. Bruce Fields return op->status; 3156085def3aSJ. Bruce Fields if (args->opcnt == 1) { 3157085def3aSJ. Bruce Fields /* 3158085def3aSJ. Bruce Fields * The original operation wasn't a solo sequence--we 3159085def3aSJ. Bruce Fields * always cache those--so this retry must not match the 3160085def3aSJ. Bruce Fields * original: 3161085def3aSJ. Bruce Fields */ 3162085def3aSJ. Bruce Fields op->status = nfserr_seq_false_retry; 3163085def3aSJ. Bruce Fields } else { 3164abfabf8cSAndy Adamson op = &args->ops[resp->opcnt++]; 3165abfabf8cSAndy Adamson op->status = nfserr_retry_uncached_rep; 3166abfabf8cSAndy Adamson nfsd4_encode_operation(resp, op); 3167074fe897SAndy Adamson } 3168abfabf8cSAndy Adamson return op->status; 3169074fe897SAndy Adamson } 3170074fe897SAndy Adamson 3171074fe897SAndy Adamson /* 3172557ce264SAndy Adamson * The sequence operation is not cached because we can use the slot and 3173557ce264SAndy Adamson * session values. 3174074fe897SAndy Adamson */ 31753ca2eb98SJ. Bruce Fields static __be32 3176bf864a31SAndy Adamson nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, 3177bf864a31SAndy Adamson struct nfsd4_sequence *seq) 3178074fe897SAndy Adamson { 3179557ce264SAndy Adamson struct nfsd4_slot *slot = resp->cstate.slot; 3180bddfdbcdSChuck Lever struct xdr_stream *xdr = resp->xdr; 3181f5236013SJ. Bruce Fields __be32 *p; 3182074fe897SAndy Adamson __be32 status; 3183074fe897SAndy Adamson 3184557ce264SAndy Adamson dprintk("--> %s slot %p\n", __func__, slot); 3185074fe897SAndy Adamson 3186abfabf8cSAndy Adamson status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); 31870da7b19cSJ. Bruce Fields if (status) 3188abfabf8cSAndy Adamson return status; 3189074fe897SAndy Adamson 3190f5236013SJ. Bruce Fields p = xdr_reserve_space(xdr, slot->sl_datalen); 3191f5236013SJ. Bruce Fields if (!p) { 3192f5236013SJ. Bruce Fields WARN_ON_ONCE(1); 3193f5236013SJ. Bruce Fields return nfserr_serverfault; 3194f5236013SJ. Bruce Fields } 3195f5236013SJ. Bruce Fields xdr_encode_opaque_fixed(p, slot->sl_data, slot->sl_datalen); 3196f5236013SJ. Bruce Fields xdr_commit_encode(xdr); 3197074fe897SAndy Adamson 3198557ce264SAndy Adamson resp->opcnt = slot->sl_opcnt; 3199f5236013SJ. Bruce Fields return slot->sl_status; 3200074fe897SAndy Adamson } 3201074fe897SAndy Adamson 32020733d213SAndy Adamson /* 32030733d213SAndy Adamson * Set the exchange_id flags returned by the server. 32040733d213SAndy Adamson */ 32050733d213SAndy Adamson static void 32060733d213SAndy Adamson nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) 32070733d213SAndy Adamson { 32089cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 32099cf514ccSChristoph Hellwig new->cl_exchange_flags |= EXCHGID4_FLAG_USE_PNFS_MDS; 32109cf514ccSChristoph Hellwig #else 32110733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; 32129cf514ccSChristoph Hellwig #endif 32130733d213SAndy Adamson 32140733d213SAndy Adamson /* Referrals are supported, Migration is not. */ 32150733d213SAndy Adamson new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; 32160733d213SAndy Adamson 32170733d213SAndy Adamson /* set the wire flags to return to client. */ 32180733d213SAndy Adamson clid->flags = new->cl_exchange_flags; 32190733d213SAndy Adamson } 32200733d213SAndy Adamson 32214eaea134SJ. Bruce Fields static bool client_has_openowners(struct nfs4_client *clp) 32224eaea134SJ. Bruce Fields { 32234eaea134SJ. Bruce Fields struct nfs4_openowner *oo; 32244eaea134SJ. Bruce Fields 32254eaea134SJ. Bruce Fields list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) { 32264eaea134SJ. Bruce Fields if (!list_empty(&oo->oo_owner.so_stateids)) 32274eaea134SJ. Bruce Fields return true; 32284eaea134SJ. Bruce Fields } 32294eaea134SJ. Bruce Fields return false; 32304eaea134SJ. Bruce Fields } 32314eaea134SJ. Bruce Fields 3232631fc9eaSJ. Bruce Fields static bool client_has_state(struct nfs4_client *clp) 3233631fc9eaSJ. Bruce Fields { 32344eaea134SJ. Bruce Fields return client_has_openowners(clp) 323547e970beSKinglong Mee #ifdef CONFIG_NFSD_PNFS 323647e970beSKinglong Mee || !list_empty(&clp->cl_lo_states) 323747e970beSKinglong Mee #endif 32386eccece9SJ. Bruce Fields || !list_empty(&clp->cl_delegations) 3239e0639dc5SOlga Kornievskaia || !list_empty(&clp->cl_sessions) 3240e0639dc5SOlga Kornievskaia || !list_empty(&clp->async_copies); 3241631fc9eaSJ. Bruce Fields } 3242631fc9eaSJ. Bruce Fields 324379123444SJ. Bruce Fields static __be32 copy_impl_id(struct nfs4_client *clp, 324479123444SJ. Bruce Fields struct nfsd4_exchange_id *exid) 324579123444SJ. Bruce Fields { 324679123444SJ. Bruce Fields if (!exid->nii_domain.data) 324779123444SJ. Bruce Fields return 0; 324879123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_domain, &exid->nii_domain, GFP_KERNEL); 324979123444SJ. Bruce Fields if (!clp->cl_nii_domain.data) 325079123444SJ. Bruce Fields return nfserr_jukebox; 325179123444SJ. Bruce Fields xdr_netobj_dup(&clp->cl_nii_name, &exid->nii_name, GFP_KERNEL); 325279123444SJ. Bruce Fields if (!clp->cl_nii_name.data) 325379123444SJ. Bruce Fields return nfserr_jukebox; 3254e29f4703SArnd Bergmann clp->cl_nii_time = exid->nii_time; 325579123444SJ. Bruce Fields return 0; 325679123444SJ. Bruce Fields } 325779123444SJ. Bruce Fields 3258b37ad28bSAl Viro __be32 3259eb69853dSChristoph Hellwig nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3260eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3261069b6ad4SAndy Adamson { 3262eb69853dSChristoph Hellwig struct nfsd4_exchange_id *exid = &u->exchange_id; 32633dbacee6STrond Myklebust struct nfs4_client *conf, *new; 32643dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 326557b7b43bSJ. Bruce Fields __be32 status; 3266363168b4SJeff Layton char addr_str[INET6_ADDRSTRLEN]; 32670733d213SAndy Adamson nfs4_verifier verf = exid->verifier; 3268363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 326983e08fd4SJ. Bruce Fields bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; 3270c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 32710733d213SAndy Adamson 3272363168b4SJeff Layton rpc_ntop(sa, addr_str, sizeof(addr_str)); 32730733d213SAndy Adamson dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " 3274523ec6edSChuck Lever "ip_addr=%s flags %x, spa_how %u\n", 32750733d213SAndy Adamson __func__, rqstp, exid, exid->clname.len, exid->clname.data, 3276363168b4SJeff Layton addr_str, exid->flags, exid->spa_how); 32770733d213SAndy Adamson 3278a084daf5SJ. Bruce Fields if (exid->flags & ~EXCHGID4_FLAG_MASK_A) 32790733d213SAndy Adamson return nfserr_inval; 32800733d213SAndy Adamson 328150c7b948SJ. Bruce Fields new = create_client(exid->clname, rqstp, &verf); 328250c7b948SJ. Bruce Fields if (new == NULL) 328350c7b948SJ. Bruce Fields return nfserr_jukebox; 328479123444SJ. Bruce Fields status = copy_impl_id(new, exid); 328579123444SJ. Bruce Fields if (status) 328679123444SJ. Bruce Fields goto out_nolock; 328750c7b948SJ. Bruce Fields 32880733d213SAndy Adamson switch (exid->spa_how) { 328957266a6eSJ. Bruce Fields case SP4_MACH_CRED: 3290ed941643SAndrew Elble exid->spo_must_enforce[0] = 0; 3291ed941643SAndrew Elble exid->spo_must_enforce[1] = ( 3292ed941643SAndrew Elble 1 << (OP_BIND_CONN_TO_SESSION - 32) | 3293ed941643SAndrew Elble 1 << (OP_EXCHANGE_ID - 32) | 3294ed941643SAndrew Elble 1 << (OP_CREATE_SESSION - 32) | 3295ed941643SAndrew Elble 1 << (OP_DESTROY_SESSION - 32) | 3296ed941643SAndrew Elble 1 << (OP_DESTROY_CLIENTID - 32)); 3297ed941643SAndrew Elble 3298ed941643SAndrew Elble exid->spo_must_allow[0] &= (1 << (OP_CLOSE) | 3299ed941643SAndrew Elble 1 << (OP_OPEN_DOWNGRADE) | 3300ed941643SAndrew Elble 1 << (OP_LOCKU) | 3301ed941643SAndrew Elble 1 << (OP_DELEGRETURN)); 3302ed941643SAndrew Elble 3303ed941643SAndrew Elble exid->spo_must_allow[1] &= ( 3304ed941643SAndrew Elble 1 << (OP_TEST_STATEID - 32) | 3305ed941643SAndrew Elble 1 << (OP_FREE_STATEID - 32)); 330650c7b948SJ. Bruce Fields if (!svc_rqst_integrity_protected(rqstp)) { 330750c7b948SJ. Bruce Fields status = nfserr_inval; 330850c7b948SJ. Bruce Fields goto out_nolock; 330950c7b948SJ. Bruce Fields } 3310920dd9bbSJ. Bruce Fields /* 3311920dd9bbSJ. Bruce Fields * Sometimes userspace doesn't give us a principal. 3312920dd9bbSJ. Bruce Fields * Which is a bug, really. Anyway, we can't enforce 3313920dd9bbSJ. Bruce Fields * MACH_CRED in that case, better to give up now: 3314920dd9bbSJ. Bruce Fields */ 3315414ca017SJ. Bruce Fields if (!new->cl_cred.cr_principal && 3316414ca017SJ. Bruce Fields !new->cl_cred.cr_raw_principal) { 3317920dd9bbSJ. Bruce Fields status = nfserr_serverfault; 3318920dd9bbSJ. Bruce Fields goto out_nolock; 3319920dd9bbSJ. Bruce Fields } 332050c7b948SJ. Bruce Fields new->cl_mach_cred = true; 332176c50eb7SGustavo A. R. Silva break; 33220733d213SAndy Adamson case SP4_NONE: 33230733d213SAndy Adamson break; 3324063b0fb9SJ. Bruce Fields default: /* checked by xdr code */ 3325063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 3326df561f66SGustavo A. R. Silva fallthrough; 33270733d213SAndy Adamson case SP4_SSV: 33288edf4b02SKinglong Mee status = nfserr_encr_alg_unsupp; 33298edf4b02SKinglong Mee goto out_nolock; 33300733d213SAndy Adamson } 33310733d213SAndy Adamson 33322dbb269dSJ. Bruce Fields /* Cases below refer to rfc 5661 section 18.35.4: */ 33333dbacee6STrond Myklebust spin_lock(&nn->client_lock); 3334382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&exid->clname, nn); 33350733d213SAndy Adamson if (conf) { 333683e08fd4SJ. Bruce Fields bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); 333783e08fd4SJ. Bruce Fields bool verfs_match = same_verf(&verf, &conf->cl_verifier); 333883e08fd4SJ. Bruce Fields 3339136e658dSJ. Bruce Fields if (update) { 3340136e658dSJ. Bruce Fields if (!clp_used_exchangeid(conf)) { /* buggy client */ 33412dbb269dSJ. Bruce Fields status = nfserr_inval; 3342e203d506SJ. Bruce Fields goto out; 3343e203d506SJ. Bruce Fields } 3344dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) { 334557266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 334657266a6eSJ. Bruce Fields goto out; 334757266a6eSJ. Bruce Fields } 33482dbb269dSJ. Bruce Fields if (!creds_match) { /* case 9 */ 33490733d213SAndy Adamson status = nfserr_perm; 33500733d213SAndy Adamson goto out; 33510733d213SAndy Adamson } 33522dbb269dSJ. Bruce Fields if (!verfs_match) { /* case 8 */ 33530733d213SAndy Adamson status = nfserr_not_same; 33540733d213SAndy Adamson goto out; 33550733d213SAndy Adamson } 3356136e658dSJ. Bruce Fields /* case 6 */ 33570733d213SAndy Adamson exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; 3358e8f80c55SChuck Lever trace_nfsd_clid_confirmed_r(conf); 33590733d213SAndy Adamson goto out_copy; 33606ddbbbfeSMike Sager } 3361136e658dSJ. Bruce Fields if (!creds_match) { /* case 3 */ 3362631fc9eaSJ. Bruce Fields if (client_has_state(conf)) { 3363136e658dSJ. Bruce Fields status = nfserr_clid_inuse; 336427787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 3365136e658dSJ. Bruce Fields goto out; 3366136e658dSJ. Bruce Fields } 3367b9831b59SJ. Bruce Fields goto out_new; 3368631fc9eaSJ. Bruce Fields } 3369136e658dSJ. Bruce Fields if (verfs_match) { /* case 2 */ 33700f1ba0efSJ. Bruce Fields conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; 3371e8f80c55SChuck Lever trace_nfsd_clid_confirmed_r(conf); 3372136e658dSJ. Bruce Fields goto out_copy; 3373136e658dSJ. Bruce Fields } 33742dbb269dSJ. Bruce Fields /* case 5, client reboot */ 3375744ea54cSChuck Lever trace_nfsd_clid_verf_mismatch(conf, rqstp, &verf); 33763dbacee6STrond Myklebust conf = NULL; 33770733d213SAndy Adamson goto out_new; 33780733d213SAndy Adamson } 33796ddbbbfeSMike Sager 33802dbb269dSJ. Bruce Fields if (update) { /* case 7 */ 33810733d213SAndy Adamson status = nfserr_noent; 33820733d213SAndy Adamson goto out; 33830733d213SAndy Adamson } 33840733d213SAndy Adamson 3385a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&exid->clname, nn); 33862dbb269dSJ. Bruce Fields if (unconf) /* case 4, possible retry or client restart */ 33873dbacee6STrond Myklebust unhash_client_locked(unconf); 33880733d213SAndy Adamson 3389e8f80c55SChuck Lever /* case 1, new owner ID */ 3390e8f80c55SChuck Lever trace_nfsd_clid_fresh(new); 3391e8f80c55SChuck Lever 33920733d213SAndy Adamson out_new: 3393fd699b8aSJeff Layton if (conf) { 3394fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 3395fd699b8aSJeff Layton if (status) 3396fd699b8aSJeff Layton goto out; 33972958d2eeSChuck Lever trace_nfsd_clid_replaced(&conf->cl_clientid); 3398fd699b8aSJeff Layton } 33994f540e29SJ. Bruce Fields new->cl_minorversion = cstate->minorversion; 3400ed941643SAndrew Elble new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; 3401ed941643SAndrew Elble new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1]; 34020733d213SAndy Adamson 3403ac55fdc4SJeff Layton add_to_unconfirmed(new); 34043dbacee6STrond Myklebust swap(new, conf); 34050733d213SAndy Adamson out_copy: 34065cc40fd7STrond Myklebust exid->clientid.cl_boot = conf->cl_clientid.cl_boot; 34075cc40fd7STrond Myklebust exid->clientid.cl_id = conf->cl_clientid.cl_id; 34080733d213SAndy Adamson 34095cc40fd7STrond Myklebust exid->seqid = conf->cl_cs_slot.sl_seqid + 1; 34105cc40fd7STrond Myklebust nfsd4_set_ex_flags(conf, exid); 34110733d213SAndy Adamson 34120733d213SAndy Adamson dprintk("nfsd4_exchange_id seqid %d flags %x\n", 34135cc40fd7STrond Myklebust conf->cl_cs_slot.sl_seqid, conf->cl_exchange_flags); 34140733d213SAndy Adamson status = nfs_ok; 34150733d213SAndy Adamson 34160733d213SAndy Adamson out: 34173dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 341850c7b948SJ. Bruce Fields out_nolock: 34195cc40fd7STrond Myklebust if (new) 34203dbacee6STrond Myklebust expire_client(new); 3421e8f80c55SChuck Lever if (unconf) { 3422e8f80c55SChuck Lever trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); 34233dbacee6STrond Myklebust expire_client(unconf); 3424e8f80c55SChuck Lever } 34250733d213SAndy Adamson return status; 3426069b6ad4SAndy Adamson } 3427069b6ad4SAndy Adamson 342857b7b43bSJ. Bruce Fields static __be32 342988e588d5SAndy Adamson check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) 3430b85d4c01SBenny Halevy { 343188e588d5SAndy Adamson dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, 343288e588d5SAndy Adamson slot_seqid); 3433b85d4c01SBenny Halevy 3434b85d4c01SBenny Halevy /* The slot is in use, and no response has been sent. */ 343588e588d5SAndy Adamson if (slot_inuse) { 343688e588d5SAndy Adamson if (seqid == slot_seqid) 3437b85d4c01SBenny Halevy return nfserr_jukebox; 3438b85d4c01SBenny Halevy else 3439b85d4c01SBenny Halevy return nfserr_seq_misordered; 3440b85d4c01SBenny Halevy } 3441f6d82485SJ. Bruce Fields /* Note unsigned 32-bit arithmetic handles wraparound: */ 344288e588d5SAndy Adamson if (likely(seqid == slot_seqid + 1)) 3443b85d4c01SBenny Halevy return nfs_ok; 344488e588d5SAndy Adamson if (seqid == slot_seqid) 3445b85d4c01SBenny Halevy return nfserr_replay_cache; 3446b85d4c01SBenny Halevy return nfserr_seq_misordered; 3447b85d4c01SBenny Halevy } 3448b85d4c01SBenny Halevy 344949557cc7SAndy Adamson /* 345049557cc7SAndy Adamson * Cache the create session result into the create session single DRC 345149557cc7SAndy Adamson * slot cache by saving the xdr structure. sl_seqid has been set. 345249557cc7SAndy Adamson * Do this for solo or embedded create session operations. 345349557cc7SAndy Adamson */ 345449557cc7SAndy Adamson static void 345549557cc7SAndy Adamson nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, 345657b7b43bSJ. Bruce Fields struct nfsd4_clid_slot *slot, __be32 nfserr) 345749557cc7SAndy Adamson { 345849557cc7SAndy Adamson slot->sl_status = nfserr; 345949557cc7SAndy Adamson memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); 346049557cc7SAndy Adamson } 346149557cc7SAndy Adamson 346249557cc7SAndy Adamson static __be32 346349557cc7SAndy Adamson nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, 346449557cc7SAndy Adamson struct nfsd4_clid_slot *slot) 346549557cc7SAndy Adamson { 346649557cc7SAndy Adamson memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); 346749557cc7SAndy Adamson return slot->sl_status; 346849557cc7SAndy Adamson } 346949557cc7SAndy Adamson 34701b74c25bSMi Jinlong #define NFSD_MIN_REQ_HDR_SEQ_SZ ((\ 34711b74c25bSMi Jinlong 2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \ 34721b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 34731b74c25bSMi Jinlong 3 + /* version, opcount, opcode */ \ 34741b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 34751b74c25bSMi Jinlong /* seqid, slotID, slotID, cache */ \ 34761b74c25bSMi Jinlong 4 ) * sizeof(__be32)) 34771b74c25bSMi Jinlong 34781b74c25bSMi Jinlong #define NFSD_MIN_RESP_HDR_SEQ_SZ ((\ 34791b74c25bSMi Jinlong 2 + /* verifier: AUTH_NULL, length 0 */\ 34801b74c25bSMi Jinlong 1 + /* status */ \ 34811b74c25bSMi Jinlong 1 + /* MIN tag is length with zero, only length */ \ 34821b74c25bSMi Jinlong 3 + /* opcount, opcode, opstatus*/ \ 34831b74c25bSMi Jinlong XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \ 34841b74c25bSMi Jinlong /* seqid, slotID, slotID, slotID, status */ \ 34851b74c25bSMi Jinlong 5 ) * sizeof(__be32)) 34861b74c25bSMi Jinlong 348755c760cfSJ. Bruce Fields static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 34881b74c25bSMi Jinlong { 348955c760cfSJ. Bruce Fields u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 349055c760cfSJ. Bruce Fields 3491373cd409SJ. Bruce Fields if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 3492373cd409SJ. Bruce Fields return nfserr_toosmall; 3493373cd409SJ. Bruce Fields if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 3494373cd409SJ. Bruce Fields return nfserr_toosmall; 349555c760cfSJ. Bruce Fields ca->headerpadsz = 0; 349655c760cfSJ. Bruce Fields ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 349755c760cfSJ. Bruce Fields ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 349855c760cfSJ. Bruce Fields ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 349955c760cfSJ. Bruce Fields ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 350055c760cfSJ. Bruce Fields NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 350155c760cfSJ. Bruce Fields ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 350255c760cfSJ. Bruce Fields /* 350355c760cfSJ. Bruce Fields * Note decreasing slot size below client's request may make it 350455c760cfSJ. Bruce Fields * difficult for client to function correctly, whereas 350555c760cfSJ. Bruce Fields * decreasing the number of slots will (just?) affect 350655c760cfSJ. Bruce Fields * performance. When short on memory we therefore prefer to 350755c760cfSJ. Bruce Fields * decrease number of slots instead of their size. Clients that 350855c760cfSJ. Bruce Fields * request larger slots than they need will get poor results: 35097f49fd5dSNeilBrown * Note that we always allow at least one slot, because our 35107f49fd5dSNeilBrown * accounting is soft and provides no guarantees either way. 351155c760cfSJ. Bruce Fields */ 35122030ca56SNeilBrown ca->maxreqs = nfsd4_get_drc_mem(ca, nn); 351355c760cfSJ. Bruce Fields 3514373cd409SJ. Bruce Fields return nfs_ok; 35151b74c25bSMi Jinlong } 35161b74c25bSMi Jinlong 35174500632fSChuck Lever /* 35184500632fSChuck Lever * Server's NFSv4.1 backchannel support is AUTH_SYS-only for now. 35194500632fSChuck Lever * These are based on similar macros in linux/sunrpc/msg_prot.h . 35204500632fSChuck Lever */ 35214500632fSChuck Lever #define RPC_MAX_HEADER_WITH_AUTH_SYS \ 35224500632fSChuck Lever (RPC_CALLHDRSIZE + 2 * (2 + UNX_CALLSLACK)) 35234500632fSChuck Lever 35244500632fSChuck Lever #define RPC_MAX_REPHEADER_WITH_AUTH_SYS \ 35254500632fSChuck Lever (RPC_REPHDRSIZE + (2 + NUL_REPLYSLACK)) 35264500632fSChuck Lever 35278a891633SKinglong Mee #define NFSD_CB_MAX_REQ_SZ ((NFS4_enc_cb_recall_sz + \ 35284500632fSChuck Lever RPC_MAX_HEADER_WITH_AUTH_SYS) * sizeof(__be32)) 35298a891633SKinglong Mee #define NFSD_CB_MAX_RESP_SZ ((NFS4_dec_cb_recall_sz + \ 35304500632fSChuck Lever RPC_MAX_REPHEADER_WITH_AUTH_SYS) * \ 35314500632fSChuck Lever sizeof(__be32)) 35328a891633SKinglong Mee 353306b332a5SJ. Bruce Fields static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca) 353406b332a5SJ. Bruce Fields { 353506b332a5SJ. Bruce Fields ca->headerpadsz = 0; 353606b332a5SJ. Bruce Fields 35378a891633SKinglong Mee if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ) 353806b332a5SJ. Bruce Fields return nfserr_toosmall; 35398a891633SKinglong Mee if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ) 354006b332a5SJ. Bruce Fields return nfserr_toosmall; 354106b332a5SJ. Bruce Fields ca->maxresp_cached = 0; 354206b332a5SJ. Bruce Fields if (ca->maxops < 2) 354306b332a5SJ. Bruce Fields return nfserr_toosmall; 354406b332a5SJ. Bruce Fields 354506b332a5SJ. Bruce Fields return nfs_ok; 3546069b6ad4SAndy Adamson } 3547069b6ad4SAndy Adamson 3548b78724b7SJ. Bruce Fields static __be32 nfsd4_check_cb_sec(struct nfsd4_cb_sec *cbs) 3549b78724b7SJ. Bruce Fields { 3550b78724b7SJ. Bruce Fields switch (cbs->flavor) { 3551b78724b7SJ. Bruce Fields case RPC_AUTH_NULL: 3552b78724b7SJ. Bruce Fields case RPC_AUTH_UNIX: 3553b78724b7SJ. Bruce Fields return nfs_ok; 3554b78724b7SJ. Bruce Fields default: 3555b78724b7SJ. Bruce Fields /* 3556b78724b7SJ. Bruce Fields * GSS case: the spec doesn't allow us to return this 3557b78724b7SJ. Bruce Fields * error. But it also doesn't allow us not to support 3558b78724b7SJ. Bruce Fields * GSS. 3559b78724b7SJ. Bruce Fields * I'd rather this fail hard than return some error the 3560b78724b7SJ. Bruce Fields * client might think it can already handle: 3561b78724b7SJ. Bruce Fields */ 3562b78724b7SJ. Bruce Fields return nfserr_encr_alg_unsupp; 3563b78724b7SJ. Bruce Fields } 3564b78724b7SJ. Bruce Fields } 3565b78724b7SJ. Bruce Fields 3566069b6ad4SAndy Adamson __be32 3567069b6ad4SAndy Adamson nfsd4_create_session(struct svc_rqst *rqstp, 3568eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 3569069b6ad4SAndy Adamson { 3570eb69853dSChristoph Hellwig struct nfsd4_create_session *cr_ses = &u->create_session; 3571363168b4SJeff Layton struct sockaddr *sa = svc_addr(rqstp); 3572ec6b5d7bSAndy Adamson struct nfs4_client *conf, *unconf; 3573d20c11d8SJeff Layton struct nfs4_client *old = NULL; 3574ac7c46f2SJ. Bruce Fields struct nfsd4_session *new; 357581f0b2a4SJ. Bruce Fields struct nfsd4_conn *conn; 357649557cc7SAndy Adamson struct nfsd4_clid_slot *cs_slot = NULL; 357757b7b43bSJ. Bruce Fields __be32 status = 0; 35788daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3579ec6b5d7bSAndy Adamson 3580a62573dcSMi Jinlong if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 3581a62573dcSMi Jinlong return nfserr_inval; 3582b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&cr_ses->cb_sec); 3583b78724b7SJ. Bruce Fields if (status) 3584b78724b7SJ. Bruce Fields return status; 358555c760cfSJ. Bruce Fields status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 3586373cd409SJ. Bruce Fields if (status) 3587373cd409SJ. Bruce Fields return status; 358806b332a5SJ. Bruce Fields status = check_backchannel_attrs(&cr_ses->back_channel); 358906b332a5SJ. Bruce Fields if (status) 3590f403e450SKinglong Mee goto out_release_drc_mem; 359181f0b2a4SJ. Bruce Fields status = nfserr_jukebox; 359260810e54SKinglong Mee new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel); 359355c760cfSJ. Bruce Fields if (!new) 359455c760cfSJ. Bruce Fields goto out_release_drc_mem; 359581f0b2a4SJ. Bruce Fields conn = alloc_conn_from_crses(rqstp, cr_ses); 359681f0b2a4SJ. Bruce Fields if (!conn) 359781f0b2a4SJ. Bruce Fields goto out_free_session; 3598a62573dcSMi Jinlong 3599d20c11d8SJeff Layton spin_lock(&nn->client_lock); 36000a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); 36018daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&cr_ses->clientid, true, nn); 360278389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 3603ec6b5d7bSAndy Adamson 3604ec6b5d7bSAndy Adamson if (conf) { 360557266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3606dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(conf, rqstp)) 360757266a6eSJ. Bruce Fields goto out_free_conn; 360849557cc7SAndy Adamson cs_slot = &conf->cl_cs_slot; 360949557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 3610f5e22bb6SKinglong Mee if (status) { 3611f5e22bb6SKinglong Mee if (status == nfserr_replay_cache) 361249557cc7SAndy Adamson status = nfsd4_replay_create_session(cr_ses, cs_slot); 361381f0b2a4SJ. Bruce Fields goto out_free_conn; 3614ec6b5d7bSAndy Adamson } 3615ec6b5d7bSAndy Adamson } else if (unconf) { 361627787733SChuck Lever status = nfserr_clid_inuse; 3617ec6b5d7bSAndy Adamson if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || 3618363168b4SJeff Layton !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { 361927787733SChuck Lever trace_nfsd_clid_cred_mismatch(unconf, rqstp); 362081f0b2a4SJ. Bruce Fields goto out_free_conn; 3621ec6b5d7bSAndy Adamson } 362257266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3623dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(unconf, rqstp)) 362457266a6eSJ. Bruce Fields goto out_free_conn; 362549557cc7SAndy Adamson cs_slot = &unconf->cl_cs_slot; 362649557cc7SAndy Adamson status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); 362738eb76a5SAndy Adamson if (status) { 362838eb76a5SAndy Adamson /* an unconfirmed replay returns misordered */ 3629ec6b5d7bSAndy Adamson status = nfserr_seq_misordered; 363081f0b2a4SJ. Bruce Fields goto out_free_conn; 3631ec6b5d7bSAndy Adamson } 3632382a62e7SStanislav Kinsbursky old = find_confirmed_client_by_name(&unconf->cl_name, nn); 3633221a6876SJ. Bruce Fields if (old) { 3634d20c11d8SJeff Layton status = mark_client_expired_locked(old); 36357abea1e8SJeff Layton if (status) { 36367abea1e8SJeff Layton old = NULL; 3637221a6876SJ. Bruce Fields goto out_free_conn; 3638221a6876SJ. Bruce Fields } 36392958d2eeSChuck Lever trace_nfsd_clid_replaced(&old->cl_clientid); 36407abea1e8SJeff Layton } 36418f9d3d3bSJ. Bruce Fields move_to_confirmed(unconf); 3642ec6b5d7bSAndy Adamson conf = unconf; 3643ec6b5d7bSAndy Adamson } else { 3644ec6b5d7bSAndy Adamson status = nfserr_stale_clientid; 364581f0b2a4SJ. Bruce Fields goto out_free_conn; 3646ec6b5d7bSAndy Adamson } 364781f0b2a4SJ. Bruce Fields status = nfs_ok; 36484ce85c8cSChuck Lever /* Persistent sessions are not supported */ 3649408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_PERSIST; 36504ce85c8cSChuck Lever /* Upshifting from TCP to RDMA is not supported */ 3651408b79bcSJ. Bruce Fields cr_ses->flags &= ~SESSION4_RDMA; 3652408b79bcSJ. Bruce Fields 365381f0b2a4SJ. Bruce Fields init_session(rqstp, new, conf, cr_ses); 3654d20c11d8SJeff Layton nfsd4_get_session_locked(new); 365581f0b2a4SJ. Bruce Fields 3656ac7c46f2SJ. Bruce Fields memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 3657ec6b5d7bSAndy Adamson NFS4_MAX_SESSIONID_LEN); 365886c3e16cSJ. Bruce Fields cs_slot->sl_seqid++; 365949557cc7SAndy Adamson cr_ses->seqid = cs_slot->sl_seqid; 3660ec6b5d7bSAndy Adamson 3661d20c11d8SJeff Layton /* cache solo and embedded create sessions under the client_lock */ 366249557cc7SAndy Adamson nfsd4_cache_create_session(cr_ses, cs_slot, status); 3663d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 3664934bd07fSJ. Bruce Fields if (conf == unconf) 3665934bd07fSJ. Bruce Fields fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); 3666d20c11d8SJeff Layton /* init connection and backchannel */ 3667d20c11d8SJeff Layton nfsd4_init_conn(rqstp, conn, new); 3668d20c11d8SJeff Layton nfsd4_put_session(new); 3669d20c11d8SJeff Layton if (old) 3670d20c11d8SJeff Layton expire_client(old); 3671ec6b5d7bSAndy Adamson return status; 367281f0b2a4SJ. Bruce Fields out_free_conn: 3673d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 367481f0b2a4SJ. Bruce Fields free_conn(conn); 3675d20c11d8SJeff Layton if (old) 3676d20c11d8SJeff Layton expire_client(old); 367781f0b2a4SJ. Bruce Fields out_free_session: 367881f0b2a4SJ. Bruce Fields __free_session(new); 367955c760cfSJ. Bruce Fields out_release_drc_mem: 368055c760cfSJ. Bruce Fields nfsd4_put_drc_mem(&cr_ses->fore_channel); 36811ca50792SJ. Bruce Fields return status; 3682069b6ad4SAndy Adamson } 3683069b6ad4SAndy Adamson 36841d1bc8f2SJ. Bruce Fields static __be32 nfsd4_map_bcts_dir(u32 *dir) 36851d1bc8f2SJ. Bruce Fields { 36861d1bc8f2SJ. Bruce Fields switch (*dir) { 36871d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE: 36881d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK: 36891d1bc8f2SJ. Bruce Fields return nfs_ok; 36901d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_FORE_OR_BOTH: 36911d1bc8f2SJ. Bruce Fields case NFS4_CDFC4_BACK_OR_BOTH: 36921d1bc8f2SJ. Bruce Fields *dir = NFS4_CDFC4_BOTH; 36931d1bc8f2SJ. Bruce Fields return nfs_ok; 3694fc5fc5d7Szhengbin } 36951d1bc8f2SJ. Bruce Fields return nfserr_inval; 36961d1bc8f2SJ. Bruce Fields } 36971d1bc8f2SJ. Bruce Fields 3698eb69853dSChristoph Hellwig __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, 3699eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 3700eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3701cb73a9f4SJ. Bruce Fields { 3702eb69853dSChristoph Hellwig struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; 3703cb73a9f4SJ. Bruce Fields struct nfsd4_session *session = cstate->session; 3704c9a49628SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3705b78724b7SJ. Bruce Fields __be32 status; 3706cb73a9f4SJ. Bruce Fields 3707b78724b7SJ. Bruce Fields status = nfsd4_check_cb_sec(&bc->bc_cb_sec); 3708b78724b7SJ. Bruce Fields if (status) 3709b78724b7SJ. Bruce Fields return status; 3710c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3711cb73a9f4SJ. Bruce Fields session->se_cb_prog = bc->bc_cb_program; 3712cb73a9f4SJ. Bruce Fields session->se_cb_sec = bc->bc_cb_sec; 3713c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3714cb73a9f4SJ. Bruce Fields 3715cb73a9f4SJ. Bruce Fields nfsd4_probe_callback(session->se_client); 3716cb73a9f4SJ. Bruce Fields 3717cb73a9f4SJ. Bruce Fields return nfs_ok; 3718cb73a9f4SJ. Bruce Fields } 3719cb73a9f4SJ. Bruce Fields 3720c2d715a1SJ. Bruce Fields static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s) 3721c2d715a1SJ. Bruce Fields { 3722c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3723c2d715a1SJ. Bruce Fields 3724c2d715a1SJ. Bruce Fields list_for_each_entry(c, &s->se_conns, cn_persession) { 3725c2d715a1SJ. Bruce Fields if (c->cn_xprt == xpt) { 3726c2d715a1SJ. Bruce Fields return c; 3727c2d715a1SJ. Bruce Fields } 3728c2d715a1SJ. Bruce Fields } 3729c2d715a1SJ. Bruce Fields return NULL; 3730c2d715a1SJ. Bruce Fields } 3731c2d715a1SJ. Bruce Fields 3732c2d715a1SJ. Bruce Fields static __be32 nfsd4_match_existing_connection(struct svc_rqst *rqst, 373302579b2fSDai Ngo struct nfsd4_session *session, u32 req, struct nfsd4_conn **conn) 3734c2d715a1SJ. Bruce Fields { 3735c2d715a1SJ. Bruce Fields struct nfs4_client *clp = session->se_client; 3736c2d715a1SJ. Bruce Fields struct svc_xprt *xpt = rqst->rq_xprt; 3737c2d715a1SJ. Bruce Fields struct nfsd4_conn *c; 3738c2d715a1SJ. Bruce Fields __be32 status; 3739c2d715a1SJ. Bruce Fields 3740c2d715a1SJ. Bruce Fields /* Following the last paragraph of RFC 5661 Section 18.34.3: */ 3741c2d715a1SJ. Bruce Fields spin_lock(&clp->cl_lock); 3742c2d715a1SJ. Bruce Fields c = __nfsd4_find_conn(xpt, session); 3743c2d715a1SJ. Bruce Fields if (!c) 3744c2d715a1SJ. Bruce Fields status = nfserr_noent; 3745c2d715a1SJ. Bruce Fields else if (req == c->cn_flags) 3746c2d715a1SJ. Bruce Fields status = nfs_ok; 3747c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_FORE_OR_BOTH && 3748c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_BACK) 3749c2d715a1SJ. Bruce Fields status = nfs_ok; 3750c2d715a1SJ. Bruce Fields else if (req == NFS4_CDFC4_BACK_OR_BOTH && 3751c2d715a1SJ. Bruce Fields c->cn_flags != NFS4_CDFC4_FORE) 3752c2d715a1SJ. Bruce Fields status = nfs_ok; 3753c2d715a1SJ. Bruce Fields else 3754c2d715a1SJ. Bruce Fields status = nfserr_inval; 3755c2d715a1SJ. Bruce Fields spin_unlock(&clp->cl_lock); 375602579b2fSDai Ngo if (status == nfs_ok && conn) 375702579b2fSDai Ngo *conn = c; 3758c2d715a1SJ. Bruce Fields return status; 3759c2d715a1SJ. Bruce Fields } 3760c2d715a1SJ. Bruce Fields 37611d1bc8f2SJ. Bruce Fields __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, 37621d1bc8f2SJ. Bruce Fields struct nfsd4_compound_state *cstate, 3763eb69853dSChristoph Hellwig union nfsd4_op_u *u) 37641d1bc8f2SJ. Bruce Fields { 3765eb69853dSChristoph Hellwig struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; 37661d1bc8f2SJ. Bruce Fields __be32 status; 37673ba63671SJ. Bruce Fields struct nfsd4_conn *conn; 37684f6e6c17SJ. Bruce Fields struct nfsd4_session *session; 3769d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3770d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 37711d1bc8f2SJ. Bruce Fields 37721d1bc8f2SJ. Bruce Fields if (!nfsd4_last_compound_op(rqstp)) 37731d1bc8f2SJ. Bruce Fields return nfserr_not_only_op; 3774c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3775d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&bcts->sessionid, net, &status); 3776c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 37774f6e6c17SJ. Bruce Fields if (!session) 3778d4e19e70STrond Myklebust goto out_no_session; 377957266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3780dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(session->se_client, rqstp)) 378157266a6eSJ. Bruce Fields goto out; 378202579b2fSDai Ngo status = nfsd4_match_existing_connection(rqstp, session, 378302579b2fSDai Ngo bcts->dir, &conn); 378402579b2fSDai Ngo if (status == nfs_ok) { 378502579b2fSDai Ngo if (bcts->dir == NFS4_CDFC4_FORE_OR_BOTH || 378602579b2fSDai Ngo bcts->dir == NFS4_CDFC4_BACK) 378702579b2fSDai Ngo conn->cn_flags |= NFS4_CDFC4_BACK; 378802579b2fSDai Ngo nfsd4_probe_callback(session->se_client); 378902579b2fSDai Ngo goto out; 379002579b2fSDai Ngo } 379102579b2fSDai Ngo if (status == nfserr_inval) 3792c2d715a1SJ. Bruce Fields goto out; 37931d1bc8f2SJ. Bruce Fields status = nfsd4_map_bcts_dir(&bcts->dir); 37943ba63671SJ. Bruce Fields if (status) 37954f6e6c17SJ. Bruce Fields goto out; 37963ba63671SJ. Bruce Fields conn = alloc_conn(rqstp, bcts->dir); 37974f6e6c17SJ. Bruce Fields status = nfserr_jukebox; 37983ba63671SJ. Bruce Fields if (!conn) 37994f6e6c17SJ. Bruce Fields goto out; 38004f6e6c17SJ. Bruce Fields nfsd4_init_conn(rqstp, conn, session); 38014f6e6c17SJ. Bruce Fields status = nfs_ok; 38024f6e6c17SJ. Bruce Fields out: 3803d4e19e70STrond Myklebust nfsd4_put_session(session); 3804d4e19e70STrond Myklebust out_no_session: 38054f6e6c17SJ. Bruce Fields return status; 38061d1bc8f2SJ. Bruce Fields } 38071d1bc8f2SJ. Bruce Fields 3808665d5072SJ. Bruce Fields static bool nfsd4_compound_in_session(struct nfsd4_compound_state *cstate, struct nfs4_sessionid *sid) 38095d4cec2fSJ. Bruce Fields { 3810665d5072SJ. Bruce Fields if (!cstate->session) 381151d87bc2SFengguang Wu return false; 3812665d5072SJ. Bruce Fields return !memcmp(sid, &cstate->session->se_sessionid, sizeof(*sid)); 38135d4cec2fSJ. Bruce Fields } 38145d4cec2fSJ. Bruce Fields 3815069b6ad4SAndy Adamson __be32 3816eb69853dSChristoph Hellwig nfsd4_destroy_session(struct svc_rqst *r, struct nfsd4_compound_state *cstate, 3817eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3818069b6ad4SAndy Adamson { 3819ca0552f4SJ. Bruce Fields struct nfs4_sessionid *sessionid = &u->destroy_session.sessionid; 3820e10e0cfcSBenny Halevy struct nfsd4_session *ses; 3821abcdff09SJ. Bruce Fields __be32 status; 3822f0f51f5cSJ. Bruce Fields int ref_held_by_me = 0; 3823d4e19e70STrond Myklebust struct net *net = SVC_NET(r); 3824d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3825e10e0cfcSBenny Halevy 3826abcdff09SJ. Bruce Fields status = nfserr_not_only_op; 3827ca0552f4SJ. Bruce Fields if (nfsd4_compound_in_session(cstate, sessionid)) { 382857716355SJ. Bruce Fields if (!nfsd4_last_compound_op(r)) 3829abcdff09SJ. Bruce Fields goto out; 3830f0f51f5cSJ. Bruce Fields ref_held_by_me++; 383157716355SJ. Bruce Fields } 3832ca0552f4SJ. Bruce Fields dump_sessionid(__func__, sessionid); 3833c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3834ca0552f4SJ. Bruce Fields ses = find_in_sessionid_hashtbl(sessionid, net, &status); 3835abcdff09SJ. Bruce Fields if (!ses) 3836abcdff09SJ. Bruce Fields goto out_client_lock; 383757266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 3838dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(ses->se_client, r)) 3839d4e19e70STrond Myklebust goto out_put_session; 3840f0f51f5cSJ. Bruce Fields status = mark_session_dead_locked(ses, 1 + ref_held_by_me); 384166b2b9b2SJ. Bruce Fields if (status) 3842f0f51f5cSJ. Bruce Fields goto out_put_session; 3843e10e0cfcSBenny Halevy unhash_session(ses); 3844c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 3845e10e0cfcSBenny Halevy 384684f5f7ccSJ. Bruce Fields nfsd4_probe_callback_sync(ses->se_client); 384719cf5c02SJ. Bruce Fields 3848c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3849e10e0cfcSBenny Halevy status = nfs_ok; 3850f0f51f5cSJ. Bruce Fields out_put_session: 3851d4e19e70STrond Myklebust nfsd4_put_session_locked(ses); 3852abcdff09SJ. Bruce Fields out_client_lock: 3853abcdff09SJ. Bruce Fields spin_unlock(&nn->client_lock); 3854e10e0cfcSBenny Halevy out: 3855e10e0cfcSBenny Halevy return status; 3856069b6ad4SAndy Adamson } 3857069b6ad4SAndy Adamson 385857266a6eSJ. Bruce Fields static __be32 nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses) 3859328ead28SJ. Bruce Fields { 3860328ead28SJ. Bruce Fields struct nfs4_client *clp = ses->se_client; 3861a663bdd8SJ. Bruce Fields struct nfsd4_conn *c; 386257266a6eSJ. Bruce Fields __be32 status = nfs_ok; 386321b75b01SJ. Bruce Fields int ret; 3864328ead28SJ. Bruce Fields 3865328ead28SJ. Bruce Fields spin_lock(&clp->cl_lock); 3866a663bdd8SJ. Bruce Fields c = __nfsd4_find_conn(new->cn_xprt, ses); 386757266a6eSJ. Bruce Fields if (c) 386857266a6eSJ. Bruce Fields goto out_free; 386957266a6eSJ. Bruce Fields status = nfserr_conn_not_bound_to_session; 387057266a6eSJ. Bruce Fields if (clp->cl_mach_cred) 387157266a6eSJ. Bruce Fields goto out_free; 3872328ead28SJ. Bruce Fields __nfsd4_hash_conn(new, ses); 3873328ead28SJ. Bruce Fields spin_unlock(&clp->cl_lock); 387421b75b01SJ. Bruce Fields ret = nfsd4_register_conn(new); 387521b75b01SJ. Bruce Fields if (ret) 387621b75b01SJ. Bruce Fields /* oops; xprt is already down: */ 387721b75b01SJ. Bruce Fields nfsd4_conn_lost(&new->cn_xpt_user); 387857266a6eSJ. Bruce Fields return nfs_ok; 387957266a6eSJ. Bruce Fields out_free: 388057266a6eSJ. Bruce Fields spin_unlock(&clp->cl_lock); 388157266a6eSJ. Bruce Fields free_conn(new); 388257266a6eSJ. Bruce Fields return status; 3883328ead28SJ. Bruce Fields } 3884328ead28SJ. Bruce Fields 3885868b89c3SMi Jinlong static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session) 3886868b89c3SMi Jinlong { 3887868b89c3SMi Jinlong struct nfsd4_compoundargs *args = rqstp->rq_argp; 3888868b89c3SMi Jinlong 3889868b89c3SMi Jinlong return args->opcnt > session->se_fchannel.maxops; 3890868b89c3SMi Jinlong } 3891868b89c3SMi Jinlong 3892ae82a8d0SMi Jinlong static bool nfsd4_request_too_big(struct svc_rqst *rqstp, 3893ae82a8d0SMi Jinlong struct nfsd4_session *session) 3894ae82a8d0SMi Jinlong { 3895ae82a8d0SMi Jinlong struct xdr_buf *xb = &rqstp->rq_arg; 3896ae82a8d0SMi Jinlong 3897ae82a8d0SMi Jinlong return xb->len > session->se_fchannel.maxreq_sz; 3898ae82a8d0SMi Jinlong } 3899ae82a8d0SMi Jinlong 390053da6a53SJ. Bruce Fields static bool replay_matches_cache(struct svc_rqst *rqstp, 390153da6a53SJ. Bruce Fields struct nfsd4_sequence *seq, struct nfsd4_slot *slot) 390253da6a53SJ. Bruce Fields { 390353da6a53SJ. Bruce Fields struct nfsd4_compoundargs *argp = rqstp->rq_argp; 390453da6a53SJ. Bruce Fields 390553da6a53SJ. Bruce Fields if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) != 390653da6a53SJ. Bruce Fields (bool)seq->cachethis) 390753da6a53SJ. Bruce Fields return false; 390853da6a53SJ. Bruce Fields /* 39096e73e92bSScott Mayhew * If there's an error then the reply can have fewer ops than 39106e73e92bSScott Mayhew * the call. 391153da6a53SJ. Bruce Fields */ 39126e73e92bSScott Mayhew if (slot->sl_opcnt < argp->opcnt && !slot->sl_status) 39136e73e92bSScott Mayhew return false; 39146e73e92bSScott Mayhew /* 39156e73e92bSScott Mayhew * But if we cached a reply with *more* ops than the call you're 39166e73e92bSScott Mayhew * sending us now, then this new call is clearly not really a 39176e73e92bSScott Mayhew * replay of the old one: 39186e73e92bSScott Mayhew */ 39196e73e92bSScott Mayhew if (slot->sl_opcnt > argp->opcnt) 392053da6a53SJ. Bruce Fields return false; 392153da6a53SJ. Bruce Fields /* This is the only check explicitly called by spec: */ 392253da6a53SJ. Bruce Fields if (!same_creds(&rqstp->rq_cred, &slot->sl_cred)) 392353da6a53SJ. Bruce Fields return false; 392453da6a53SJ. Bruce Fields /* 392553da6a53SJ. Bruce Fields * There may be more comparisons we could actually do, but the 392653da6a53SJ. Bruce Fields * spec doesn't require us to catch every case where the calls 392753da6a53SJ. Bruce Fields * don't match (that would require caching the call as well as 392853da6a53SJ. Bruce Fields * the reply), so we don't bother. 392953da6a53SJ. Bruce Fields */ 393053da6a53SJ. Bruce Fields return true; 393153da6a53SJ. Bruce Fields } 393253da6a53SJ. Bruce Fields 3933069b6ad4SAndy Adamson __be32 3934eb69853dSChristoph Hellwig nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 3935eb69853dSChristoph Hellwig union nfsd4_op_u *u) 3936069b6ad4SAndy Adamson { 3937eb69853dSChristoph Hellwig struct nfsd4_sequence *seq = &u->sequence; 3938f9bb94c4SAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 3939bddfdbcdSChuck Lever struct xdr_stream *xdr = resp->xdr; 3940b85d4c01SBenny Halevy struct nfsd4_session *session; 3941221a6876SJ. Bruce Fields struct nfs4_client *clp; 3942b85d4c01SBenny Halevy struct nfsd4_slot *slot; 3943a663bdd8SJ. Bruce Fields struct nfsd4_conn *conn; 394457b7b43bSJ. Bruce Fields __be32 status; 394547ee5298SJ. Bruce Fields int buflen; 3946d4e19e70STrond Myklebust struct net *net = SVC_NET(rqstp); 3947d4e19e70STrond Myklebust struct nfsd_net *nn = net_generic(net, nfsd_net_id); 3948b85d4c01SBenny Halevy 3949f9bb94c4SAndy Adamson if (resp->opcnt != 1) 3950f9bb94c4SAndy Adamson return nfserr_sequence_pos; 3951f9bb94c4SAndy Adamson 3952a663bdd8SJ. Bruce Fields /* 3953a663bdd8SJ. Bruce Fields * Will be either used or freed by nfsd4_sequence_check_conn 3954a663bdd8SJ. Bruce Fields * below. 3955a663bdd8SJ. Bruce Fields */ 3956a663bdd8SJ. Bruce Fields conn = alloc_conn(rqstp, NFS4_CDFC4_FORE); 3957a663bdd8SJ. Bruce Fields if (!conn) 3958a663bdd8SJ. Bruce Fields return nfserr_jukebox; 3959a663bdd8SJ. Bruce Fields 3960c9a49628SStanislav Kinsbursky spin_lock(&nn->client_lock); 3961d4e19e70STrond Myklebust session = find_in_sessionid_hashtbl(&seq->sessionid, net, &status); 3962b85d4c01SBenny Halevy if (!session) 3963221a6876SJ. Bruce Fields goto out_no_session; 3964221a6876SJ. Bruce Fields clp = session->se_client; 3965b85d4c01SBenny Halevy 3966868b89c3SMi Jinlong status = nfserr_too_many_ops; 3967868b89c3SMi Jinlong if (nfsd4_session_too_many_ops(rqstp, session)) 396866b2b9b2SJ. Bruce Fields goto out_put_session; 3969868b89c3SMi Jinlong 3970ae82a8d0SMi Jinlong status = nfserr_req_too_big; 3971ae82a8d0SMi Jinlong if (nfsd4_request_too_big(rqstp, session)) 397266b2b9b2SJ. Bruce Fields goto out_put_session; 3973ae82a8d0SMi Jinlong 3974b85d4c01SBenny Halevy status = nfserr_badslot; 39756c18ba9fSAlexandros Batsakis if (seq->slotid >= session->se_fchannel.maxreqs) 397666b2b9b2SJ. Bruce Fields goto out_put_session; 3977b85d4c01SBenny Halevy 3978557ce264SAndy Adamson slot = session->se_slots[seq->slotid]; 3979b85d4c01SBenny Halevy dprintk("%s: slotid %d\n", __func__, seq->slotid); 3980b85d4c01SBenny Halevy 3981a8dfdaebSAndy Adamson /* We do not negotiate the number of slots yet, so set the 3982a8dfdaebSAndy Adamson * maxslots to the session maxreqs which is used to encode 3983a8dfdaebSAndy Adamson * sr_highest_slotid and the sr_target_slot id to maxslots */ 3984a8dfdaebSAndy Adamson seq->maxslots = session->se_fchannel.maxreqs; 3985a8dfdaebSAndy Adamson 398673e79482SJ. Bruce Fields status = check_slot_seqid(seq->seqid, slot->sl_seqid, 398773e79482SJ. Bruce Fields slot->sl_flags & NFSD4_SLOT_INUSE); 3988b85d4c01SBenny Halevy if (status == nfserr_replay_cache) { 3989bf5c43c8SJ. Bruce Fields status = nfserr_seq_misordered; 3990bf5c43c8SJ. Bruce Fields if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) 399166b2b9b2SJ. Bruce Fields goto out_put_session; 399253da6a53SJ. Bruce Fields status = nfserr_seq_false_retry; 399353da6a53SJ. Bruce Fields if (!replay_matches_cache(rqstp, seq, slot)) 399453da6a53SJ. Bruce Fields goto out_put_session; 3995b85d4c01SBenny Halevy cstate->slot = slot; 3996b85d4c01SBenny Halevy cstate->session = session; 39974b24ca7dSJeff Layton cstate->clp = clp; 3998da3846a2SAndy Adamson /* Return the cached reply status and set cstate->status 3999557ce264SAndy Adamson * for nfsd4_proc_compound processing */ 4000bf864a31SAndy Adamson status = nfsd4_replay_cache_entry(resp, seq); 4001da3846a2SAndy Adamson cstate->status = nfserr_replay_cache; 4002aaf84eb9SBenny Halevy goto out; 4003b85d4c01SBenny Halevy } 4004b85d4c01SBenny Halevy if (status) 400566b2b9b2SJ. Bruce Fields goto out_put_session; 4006b85d4c01SBenny Halevy 400757266a6eSJ. Bruce Fields status = nfsd4_sequence_check_conn(conn, session); 4008a663bdd8SJ. Bruce Fields conn = NULL; 400957266a6eSJ. Bruce Fields if (status) 401057266a6eSJ. Bruce Fields goto out_put_session; 4011328ead28SJ. Bruce Fields 401247ee5298SJ. Bruce Fields buflen = (seq->cachethis) ? 401347ee5298SJ. Bruce Fields session->se_fchannel.maxresp_cached : 401447ee5298SJ. Bruce Fields session->se_fchannel.maxresp_sz; 401547ee5298SJ. Bruce Fields status = (seq->cachethis) ? nfserr_rep_too_big_to_cache : 401647ee5298SJ. Bruce Fields nfserr_rep_too_big; 4017a5cddc88SJ. Bruce Fields if (xdr_restrict_buflen(xdr, buflen - rqstp->rq_auth_slack)) 401847ee5298SJ. Bruce Fields goto out_put_session; 401932aaa62eSJ. Bruce Fields svc_reserve(rqstp, buflen); 402047ee5298SJ. Bruce Fields 402147ee5298SJ. Bruce Fields status = nfs_ok; 4022b85d4c01SBenny Halevy /* Success! bump slot seqid */ 4023b85d4c01SBenny Halevy slot->sl_seqid = seq->seqid; 4024bf5c43c8SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_INUSE; 402573e79482SJ. Bruce Fields if (seq->cachethis) 402673e79482SJ. Bruce Fields slot->sl_flags |= NFSD4_SLOT_CACHETHIS; 4027bf5c43c8SJ. Bruce Fields else 4028bf5c43c8SJ. Bruce Fields slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; 4029b85d4c01SBenny Halevy 4030b85d4c01SBenny Halevy cstate->slot = slot; 4031b85d4c01SBenny Halevy cstate->session = session; 40324b24ca7dSJeff Layton cstate->clp = clp; 4033b85d4c01SBenny Halevy 4034b85d4c01SBenny Halevy out: 40355423732aSBenny Halevy switch (clp->cl_cb_state) { 40365423732aSBenny Halevy case NFSD4_CB_DOWN: 4037fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; 40385423732aSBenny Halevy break; 40395423732aSBenny Halevy case NFSD4_CB_FAULT: 4040fc0c3dd1SBenny Halevy seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; 40415423732aSBenny Halevy break; 4042fc0c3dd1SBenny Halevy default: 4043fc0c3dd1SBenny Halevy seq->status_flags = 0; 40445423732aSBenny Halevy } 40453bd64a5bSJ. Bruce Fields if (!list_empty(&clp->cl_revoked)) 40463bd64a5bSJ. Bruce Fields seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED; 4047221a6876SJ. Bruce Fields out_no_session: 40483f42d2c4SKinglong Mee if (conn) 40493f42d2c4SKinglong Mee free_conn(conn); 4050c9a49628SStanislav Kinsbursky spin_unlock(&nn->client_lock); 4051b85d4c01SBenny Halevy return status; 405266b2b9b2SJ. Bruce Fields out_put_session: 4053d4e19e70STrond Myklebust nfsd4_put_session_locked(session); 4054221a6876SJ. Bruce Fields goto out_no_session; 4055069b6ad4SAndy Adamson } 4056069b6ad4SAndy Adamson 4057b607664eSTrond Myklebust void 4058b607664eSTrond Myklebust nfsd4_sequence_done(struct nfsd4_compoundres *resp) 4059b607664eSTrond Myklebust { 4060b607664eSTrond Myklebust struct nfsd4_compound_state *cs = &resp->cstate; 4061b607664eSTrond Myklebust 4062b607664eSTrond Myklebust if (nfsd4_has_session(cs)) { 4063b607664eSTrond Myklebust if (cs->status != nfserr_replay_cache) { 4064b607664eSTrond Myklebust nfsd4_store_cache_entry(resp); 4065b607664eSTrond Myklebust cs->slot->sl_flags &= ~NFSD4_SLOT_INUSE; 4066b607664eSTrond Myklebust } 4067d4e19e70STrond Myklebust /* Drop session reference that was taken in nfsd4_sequence() */ 4068b607664eSTrond Myklebust nfsd4_put_session(cs->session); 40694b24ca7dSJeff Layton } else if (cs->clp) 40704b24ca7dSJeff Layton put_client_renew(cs->clp); 4071b607664eSTrond Myklebust } 4072b607664eSTrond Myklebust 4073345c2842SMi Jinlong __be32 4074eb69853dSChristoph Hellwig nfsd4_destroy_clientid(struct svc_rqst *rqstp, 4075eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, 4076eb69853dSChristoph Hellwig union nfsd4_op_u *u) 4077345c2842SMi Jinlong { 4078eb69853dSChristoph Hellwig struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; 40796b10ad19STrond Myklebust struct nfs4_client *conf, *unconf; 40806b10ad19STrond Myklebust struct nfs4_client *clp = NULL; 408157b7b43bSJ. Bruce Fields __be32 status = 0; 40828daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 4083345c2842SMi Jinlong 40846b10ad19STrond Myklebust spin_lock(&nn->client_lock); 40850a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(&dc->clientid, true, nn); 40868daae4dcSStanislav Kinsbursky conf = find_confirmed_client(&dc->clientid, true, nn); 408778389046SJ. Bruce Fields WARN_ON_ONCE(conf && unconf); 4088345c2842SMi Jinlong 4089345c2842SMi Jinlong if (conf) { 4090c0293b01SJ. Bruce Fields if (client_has_state(conf)) { 4091345c2842SMi Jinlong status = nfserr_clientid_busy; 4092345c2842SMi Jinlong goto out; 4093345c2842SMi Jinlong } 4094fd699b8aSJeff Layton status = mark_client_expired_locked(conf); 4095fd699b8aSJeff Layton if (status) 4096fd699b8aSJeff Layton goto out; 40976b10ad19STrond Myklebust clp = conf; 4098345c2842SMi Jinlong } else if (unconf) 4099345c2842SMi Jinlong clp = unconf; 4100345c2842SMi Jinlong else { 4101345c2842SMi Jinlong status = nfserr_stale_clientid; 4102345c2842SMi Jinlong goto out; 4103345c2842SMi Jinlong } 4104dedeb13fSAndrew Elble if (!nfsd4_mach_creds_match(clp, rqstp)) { 41056b10ad19STrond Myklebust clp = NULL; 410657266a6eSJ. Bruce Fields status = nfserr_wrong_cred; 410757266a6eSJ. Bruce Fields goto out; 410857266a6eSJ. Bruce Fields } 4109c41a9b7aSChuck Lever trace_nfsd_clid_destroyed(&clp->cl_clientid); 41106b10ad19STrond Myklebust unhash_client_locked(clp); 4111345c2842SMi Jinlong out: 41126b10ad19STrond Myklebust spin_unlock(&nn->client_lock); 41136b10ad19STrond Myklebust if (clp) 41146b10ad19STrond Myklebust expire_client(clp); 4115345c2842SMi Jinlong return status; 4116345c2842SMi Jinlong } 4117345c2842SMi Jinlong 4118069b6ad4SAndy Adamson __be32 4119eb69853dSChristoph Hellwig nfsd4_reclaim_complete(struct svc_rqst *rqstp, 4120eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 41214dc6ec00SJ. Bruce Fields { 4122eb69853dSChristoph Hellwig struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; 4123ec59659bSJ. Bruce Fields struct nfs4_client *clp = cstate->clp; 412457b7b43bSJ. Bruce Fields __be32 status = 0; 4125bcecf1ccSMi Jinlong 41264dc6ec00SJ. Bruce Fields if (rc->rca_one_fs) { 41274dc6ec00SJ. Bruce Fields if (!cstate->current_fh.fh_dentry) 41284dc6ec00SJ. Bruce Fields return nfserr_nofilehandle; 41294dc6ec00SJ. Bruce Fields /* 41304dc6ec00SJ. Bruce Fields * We don't take advantage of the rca_one_fs case. 41314dc6ec00SJ. Bruce Fields * That's OK, it's optional, we can safely ignore it. 41324dc6ec00SJ. Bruce Fields */ 41334dc6ec00SJ. Bruce Fields return nfs_ok; 41344dc6ec00SJ. Bruce Fields } 4135bcecf1ccSMi Jinlong 4136bcecf1ccSMi Jinlong status = nfserr_complete_already; 4137ec59659bSJ. Bruce Fields if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) 4138bcecf1ccSMi Jinlong goto out; 4139bcecf1ccSMi Jinlong 4140bcecf1ccSMi Jinlong status = nfserr_stale_clientid; 4141ec59659bSJ. Bruce Fields if (is_client_expired(clp)) 41424dc6ec00SJ. Bruce Fields /* 41434dc6ec00SJ. Bruce Fields * The following error isn't really legal. 41444dc6ec00SJ. Bruce Fields * But we only get here if the client just explicitly 41454dc6ec00SJ. Bruce Fields * destroyed the client. Surely it no longer cares what 41464dc6ec00SJ. Bruce Fields * error it gets back on an operation for the dead 41474dc6ec00SJ. Bruce Fields * client. 41484dc6ec00SJ. Bruce Fields */ 4149bcecf1ccSMi Jinlong goto out; 4150bcecf1ccSMi Jinlong 4151bcecf1ccSMi Jinlong status = nfs_ok; 4152cee8aa07SChuck Lever trace_nfsd_clid_reclaim_complete(&clp->cl_clientid); 4153ec59659bSJ. Bruce Fields nfsd4_client_record_create(clp); 4154ec59659bSJ. Bruce Fields inc_reclaim_complete(clp); 4155bcecf1ccSMi Jinlong out: 4156bcecf1ccSMi Jinlong return status; 41574dc6ec00SJ. Bruce Fields } 41584dc6ec00SJ. Bruce Fields 41594dc6ec00SJ. Bruce Fields __be32 4160b591480bSJ.Bruce Fields nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4161eb69853dSChristoph Hellwig union nfsd4_op_u *u) 41621da177e4SLinus Torvalds { 4163eb69853dSChristoph Hellwig struct nfsd4_setclientid *setclid = &u->setclientid; 4164a084daf5SJ. Bruce Fields struct xdr_netobj clname = setclid->se_name; 41651da177e4SLinus Torvalds nfs4_verifier clverifier = setclid->se_verf; 41663dbacee6STrond Myklebust struct nfs4_client *conf, *new; 41673dbacee6STrond Myklebust struct nfs4_client *unconf = NULL; 4168b37ad28bSAl Viro __be32 status; 4169c212cecfSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 4170a55370a3SNeilBrown 41715cc40fd7STrond Myklebust new = create_client(clname, rqstp, &clverifier); 41725cc40fd7STrond Myklebust if (new == NULL) 41735cc40fd7STrond Myklebust return nfserr_jukebox; 41743dbacee6STrond Myklebust spin_lock(&nn->client_lock); 4175382a62e7SStanislav Kinsbursky conf = find_confirmed_client_by_name(&clname, nn); 41762b634821SJ. Bruce Fields if (conf && client_has_state(conf)) { 41771da177e4SLinus Torvalds status = nfserr_clid_inuse; 4178e203d506SJ. Bruce Fields if (clp_used_exchangeid(conf)) 4179e203d506SJ. Bruce Fields goto out; 4180026722c2SJ. Bruce Fields if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 418127787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 41821da177e4SLinus Torvalds goto out; 41831da177e4SLinus Torvalds } 41841da177e4SLinus Torvalds } 4185a99454aaSStanislav Kinsbursky unconf = find_unconfirmed_client_by_name(&clname, nn); 41861da177e4SLinus Torvalds if (unconf) 41873dbacee6STrond Myklebust unhash_client_locked(unconf); 4188744ea54cSChuck Lever if (conf) { 4189744ea54cSChuck Lever if (same_verf(&conf->cl_verifier, &clverifier)) { 41901da177e4SLinus Torvalds copy_clid(new, conf); 419141eb1670SKinglong Mee gen_confirm(new, nn); 4192744ea54cSChuck Lever } else 4193744ea54cSChuck Lever trace_nfsd_clid_verf_mismatch(conf, rqstp, 4194744ea54cSChuck Lever &clverifier); 4195237f91c8SChuck Lever } else 4196237f91c8SChuck Lever trace_nfsd_clid_fresh(new); 41978323c3b2SJ. Bruce Fields new->cl_minorversion = 0; 41986f3d772fSTakuma Umeya gen_callback(new, setclid, rqstp); 4199ac55fdc4SJeff Layton add_to_unconfirmed(new); 42001da177e4SLinus Torvalds setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; 42011da177e4SLinus Torvalds setclid->se_clientid.cl_id = new->cl_clientid.cl_id; 42021da177e4SLinus Torvalds memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); 42035cc40fd7STrond Myklebust new = NULL; 42041da177e4SLinus Torvalds status = nfs_ok; 42051da177e4SLinus Torvalds out: 42063dbacee6STrond Myklebust spin_unlock(&nn->client_lock); 42075cc40fd7STrond Myklebust if (new) 42085cc40fd7STrond Myklebust free_client(new); 4209237f91c8SChuck Lever if (unconf) { 4210237f91c8SChuck Lever trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); 42113dbacee6STrond Myklebust expire_client(unconf); 4212237f91c8SChuck Lever } 42131da177e4SLinus Torvalds return status; 42141da177e4SLinus Torvalds } 42151da177e4SLinus Torvalds 4216b37ad28bSAl Viro __be32 4217b591480bSJ.Bruce Fields nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 4218b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 4219eb69853dSChristoph Hellwig union nfsd4_op_u *u) 42201da177e4SLinus Torvalds { 4221eb69853dSChristoph Hellwig struct nfsd4_setclientid_confirm *setclientid_confirm = 4222eb69853dSChristoph Hellwig &u->setclientid_confirm; 422321ab45a4SNeilBrown struct nfs4_client *conf, *unconf; 4224d20c11d8SJeff Layton struct nfs4_client *old = NULL; 42251da177e4SLinus Torvalds nfs4_verifier confirm = setclientid_confirm->sc_confirm; 42261da177e4SLinus Torvalds clientid_t * clid = &setclientid_confirm->sc_clientid; 4227b37ad28bSAl Viro __be32 status; 42287f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 42291da177e4SLinus Torvalds 42302c142baaSStanislav Kinsbursky if (STALE_CLIENTID(clid, nn)) 42311da177e4SLinus Torvalds return nfserr_stale_clientid; 423221ab45a4SNeilBrown 4233d20c11d8SJeff Layton spin_lock(&nn->client_lock); 42348daae4dcSStanislav Kinsbursky conf = find_confirmed_client(clid, false, nn); 42350a7ec377SStanislav Kinsbursky unconf = find_unconfirmed_client(clid, false, nn); 4236a186e767SJ. Bruce Fields /* 42378695b90aSJ. Bruce Fields * We try hard to give out unique clientid's, so if we get an 42388695b90aSJ. Bruce Fields * attempt to confirm the same clientid with a different cred, 4239f984a7ceSJ. Bruce Fields * the client may be buggy; this should never happen. 4240f984a7ceSJ. Bruce Fields * 4241f984a7ceSJ. Bruce Fields * Nevertheless, RFC 7530 recommends INUSE for this case: 4242a186e767SJ. Bruce Fields */ 4243f984a7ceSJ. Bruce Fields status = nfserr_clid_inuse; 424427787733SChuck Lever if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { 424527787733SChuck Lever trace_nfsd_clid_cred_mismatch(unconf, rqstp); 42468695b90aSJ. Bruce Fields goto out; 424727787733SChuck Lever } 424827787733SChuck Lever if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) { 424927787733SChuck Lever trace_nfsd_clid_cred_mismatch(conf, rqstp); 42508695b90aSJ. Bruce Fields goto out; 425127787733SChuck Lever } 425290d700b7SJ. Bruce Fields if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { 42537d22fc11SJ. Bruce Fields if (conf && same_verf(&confirm, &conf->cl_confirm)) { 425490d700b7SJ. Bruce Fields status = nfs_ok; 4255237f91c8SChuck Lever } else 425690d700b7SJ. Bruce Fields status = nfserr_stale_clientid; 425790d700b7SJ. Bruce Fields goto out; 425890d700b7SJ. Bruce Fields } 425990d700b7SJ. Bruce Fields status = nfs_ok; 4260237f91c8SChuck Lever if (conf) { 4261d20c11d8SJeff Layton old = unconf; 4262d20c11d8SJeff Layton unhash_client_locked(old); 42635a3c9d71SJ. Bruce Fields nfsd4_change_callback(conf, &unconf->cl_cb_conn); 4264237f91c8SChuck Lever } else { 4265d20c11d8SJeff Layton old = find_confirmed_client_by_name(&unconf->cl_name, nn); 4266d20c11d8SJeff Layton if (old) { 42672b634821SJ. Bruce Fields status = nfserr_clid_inuse; 42682b634821SJ. Bruce Fields if (client_has_state(old) 42692b634821SJ. Bruce Fields && !same_creds(&unconf->cl_cred, 4270ab451ea9SDai Ngo &old->cl_cred)) { 4271ab451ea9SDai Ngo old = NULL; 42722b634821SJ. Bruce Fields goto out; 4273ab451ea9SDai Ngo } 4274d20c11d8SJeff Layton status = mark_client_expired_locked(old); 42757abea1e8SJeff Layton if (status) { 42767abea1e8SJeff Layton old = NULL; 4277221a6876SJ. Bruce Fields goto out; 4278221a6876SJ. Bruce Fields } 42792958d2eeSChuck Lever trace_nfsd_clid_replaced(&old->cl_clientid); 42807abea1e8SJeff Layton } 42811da177e4SLinus Torvalds move_to_confirmed(unconf); 4282d20c11d8SJeff Layton conf = unconf; 428308e8987cSNeilBrown } 4284d20c11d8SJeff Layton get_client_locked(conf); 4285d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4286934bd07fSJ. Bruce Fields if (conf == unconf) 4287934bd07fSJ. Bruce Fields fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); 4288d20c11d8SJeff Layton nfsd4_probe_callback(conf); 4289d20c11d8SJeff Layton spin_lock(&nn->client_lock); 4290d20c11d8SJeff Layton put_client_renew_locked(conf); 42911da177e4SLinus Torvalds out: 4292d20c11d8SJeff Layton spin_unlock(&nn->client_lock); 4293d20c11d8SJeff Layton if (old) 4294d20c11d8SJeff Layton expire_client(old); 42951da177e4SLinus Torvalds return status; 42961da177e4SLinus Torvalds } 42971da177e4SLinus Torvalds 429832513b40SJ. Bruce Fields static struct nfs4_file *nfsd4_alloc_file(void) 42991da177e4SLinus Torvalds { 430032513b40SJ. Bruce Fields return kmem_cache_alloc(file_slab, GFP_KERNEL); 430132513b40SJ. Bruce Fields } 430232513b40SJ. Bruce Fields 430332513b40SJ. Bruce Fields /* OPEN Share state helper functions */ 4304950e0118STrond Myklebust 430581a21fa3SChuck Lever static void nfsd4_file_init(const struct svc_fh *fh, struct nfs4_file *fp) 430681a21fa3SChuck Lever { 4307818a34ebSElena Reshetova refcount_set(&fp->fi_ref, 1); 43081d31a253STrond Myklebust spin_lock_init(&fp->fi_lock); 43098beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_stateids); 43108beefa24SNeilBrown INIT_LIST_HEAD(&fp->fi_delegations); 43118287f009SSachin Bhamare INIT_LIST_HEAD(&fp->fi_clnt_odstate); 4312f9b60e22SJ. Bruce Fields fh_copy_shallow(&fp->fi_fhandle, &fh->fh_handle); 43130c637be8SJeff Layton fp->fi_deleg_file = NULL; 431447f9940cSMeelap Shah fp->fi_had_conflict = false; 4315baeb4ff0SJeff Layton fp->fi_share_deny = 0; 4316f9d7562fSJ. Bruce Fields memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); 4317f9d7562fSJ. Bruce Fields memset(fp->fi_access, 0, sizeof(fp->fi_access)); 4318a0ce4837SJ. Bruce Fields fp->fi_aliased = false; 4319a0ce4837SJ. Bruce Fields fp->fi_inode = d_inode(fh->fh_dentry); 43209cf514ccSChristoph Hellwig #ifdef CONFIG_NFSD_PNFS 43219cf514ccSChristoph Hellwig INIT_LIST_HEAD(&fp->fi_lo_states); 4322c5c707f9SChristoph Hellwig atomic_set(&fp->fi_lo_recalls, 0); 43239cf514ccSChristoph Hellwig #endif 43241da177e4SLinus Torvalds } 43251da177e4SLinus Torvalds 4326e8ff2a84SJ. Bruce Fields void 4327e60d4398SNeilBrown nfsd4_free_slabs(void) 4328e60d4398SNeilBrown { 43299258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4330abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 4331abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4332abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4333abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4334abf1135bSChristoph Hellwig kmem_cache_destroy(deleg_slab); 43359258a2d5SJeff Layton kmem_cache_destroy(odstate_slab); 4336e60d4398SNeilBrown } 43371da177e4SLinus Torvalds 433872083396SBryan Schumaker int 43391da177e4SLinus Torvalds nfsd4_init_slabs(void) 43401da177e4SLinus Torvalds { 43419258a2d5SJeff Layton client_slab = kmem_cache_create("nfsd4_clients", 43429258a2d5SJeff Layton sizeof(struct nfs4_client), 0, 0, NULL); 43439258a2d5SJeff Layton if (client_slab == NULL) 43449258a2d5SJeff Layton goto out; 4345fe0750e5SJ. Bruce Fields openowner_slab = kmem_cache_create("nfsd4_openowners", 4346fe0750e5SJ. Bruce Fields sizeof(struct nfs4_openowner), 0, 0, NULL); 4347fe0750e5SJ. Bruce Fields if (openowner_slab == NULL) 43489258a2d5SJeff Layton goto out_free_client_slab; 4349fe0750e5SJ. Bruce Fields lockowner_slab = kmem_cache_create("nfsd4_lockowners", 43503c40794bSYanchuan Nian sizeof(struct nfs4_lockowner), 0, 0, NULL); 4351fe0750e5SJ. Bruce Fields if (lockowner_slab == NULL) 4352abf1135bSChristoph Hellwig goto out_free_openowner_slab; 4353e60d4398SNeilBrown file_slab = kmem_cache_create("nfsd4_files", 435420c2df83SPaul Mundt sizeof(struct nfs4_file), 0, 0, NULL); 4355e60d4398SNeilBrown if (file_slab == NULL) 4356abf1135bSChristoph Hellwig goto out_free_lockowner_slab; 43575ac049acSNeilBrown stateid_slab = kmem_cache_create("nfsd4_stateids", 4358dcef0413SJ. Bruce Fields sizeof(struct nfs4_ol_stateid), 0, 0, NULL); 43595ac049acSNeilBrown if (stateid_slab == NULL) 4360abf1135bSChristoph Hellwig goto out_free_file_slab; 43615b2d21c1SNeilBrown deleg_slab = kmem_cache_create("nfsd4_delegations", 436220c2df83SPaul Mundt sizeof(struct nfs4_delegation), 0, 0, NULL); 43635b2d21c1SNeilBrown if (deleg_slab == NULL) 4364abf1135bSChristoph Hellwig goto out_free_stateid_slab; 43658287f009SSachin Bhamare odstate_slab = kmem_cache_create("nfsd4_odstate", 43668287f009SSachin Bhamare sizeof(struct nfs4_clnt_odstate), 0, 0, NULL); 43678287f009SSachin Bhamare if (odstate_slab == NULL) 43688287f009SSachin Bhamare goto out_free_deleg_slab; 4369e60d4398SNeilBrown return 0; 4370abf1135bSChristoph Hellwig 43718287f009SSachin Bhamare out_free_deleg_slab: 43728287f009SSachin Bhamare kmem_cache_destroy(deleg_slab); 4373abf1135bSChristoph Hellwig out_free_stateid_slab: 4374abf1135bSChristoph Hellwig kmem_cache_destroy(stateid_slab); 4375abf1135bSChristoph Hellwig out_free_file_slab: 4376abf1135bSChristoph Hellwig kmem_cache_destroy(file_slab); 4377abf1135bSChristoph Hellwig out_free_lockowner_slab: 4378abf1135bSChristoph Hellwig kmem_cache_destroy(lockowner_slab); 4379abf1135bSChristoph Hellwig out_free_openowner_slab: 4380abf1135bSChristoph Hellwig kmem_cache_destroy(openowner_slab); 43819258a2d5SJeff Layton out_free_client_slab: 43829258a2d5SJeff Layton kmem_cache_destroy(client_slab); 4383abf1135bSChristoph Hellwig out: 43841da177e4SLinus Torvalds return -ENOMEM; 43851da177e4SLinus Torvalds } 43861da177e4SLinus Torvalds 43877746b32fSDai Ngo static unsigned long 4388a1049eb4SDai Ngo nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) 43897746b32fSDai Ngo { 439044df6f43SDai Ngo int count; 43917746b32fSDai Ngo struct nfsd_net *nn = container_of(shrink, 43927746b32fSDai Ngo struct nfsd_net, nfsd_client_shrinker); 43937746b32fSDai Ngo 439444df6f43SDai Ngo count = atomic_read(&nn->nfsd_courtesy_clients); 439544df6f43SDai Ngo if (!count) 439644df6f43SDai Ngo count = atomic_long_read(&num_delegations); 439744df6f43SDai Ngo if (count) 43987c24fa22SDai Ngo queue_work(laundry_wq, &nn->nfsd_shrinker_work); 439944df6f43SDai Ngo return (unsigned long)count; 44007746b32fSDai Ngo } 44017746b32fSDai Ngo 44027746b32fSDai Ngo static unsigned long 4403a1049eb4SDai Ngo nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc) 44047746b32fSDai Ngo { 44057746b32fSDai Ngo return SHRINK_STOP; 44067746b32fSDai Ngo } 44077746b32fSDai Ngo 4408f385f7d2SDai Ngo void 44097746b32fSDai Ngo nfsd4_init_leases_net(struct nfsd_net *nn) 44106867137eSDai Ngo { 44114271c2c0SDai Ngo struct sysinfo si; 44124271c2c0SDai Ngo u64 max_clients; 44134271c2c0SDai Ngo 44146867137eSDai Ngo nn->nfsd4_lease = 90; /* default lease time */ 44156867137eSDai Ngo nn->nfsd4_grace = 90; 44166867137eSDai Ngo nn->somebody_reclaimed = false; 44176867137eSDai Ngo nn->track_reclaim_completes = false; 4418a251c17aSJason A. Donenfeld nn->clverifier_counter = get_random_u32(); 4419a251c17aSJason A. Donenfeld nn->clientid_base = get_random_u32(); 44206867137eSDai Ngo nn->clientid_counter = nn->clientid_base + 1; 44216867137eSDai Ngo nn->s2s_cp_cl_id = nn->clientid_counter++; 44220926c395SDai Ngo 44230926c395SDai Ngo atomic_set(&nn->nfs4_client_count, 0); 44244271c2c0SDai Ngo si_meminfo(&si); 44254271c2c0SDai Ngo max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024); 44264271c2c0SDai Ngo max_clients *= NFS4_CLIENTS_PER_GB; 44274271c2c0SDai Ngo nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); 44283a4ea23dSDai Ngo 44293a4ea23dSDai Ngo atomic_set(&nn->nfsd_courtesy_clients, 0); 44306867137eSDai Ngo } 44316867137eSDai Ngo 4432ff194bd9SJ. Bruce Fields static void init_nfs4_replay(struct nfs4_replay *rp) 4433ff194bd9SJ. Bruce Fields { 4434ff194bd9SJ. Bruce Fields rp->rp_status = nfserr_serverfault; 4435ff194bd9SJ. Bruce Fields rp->rp_buflen = 0; 4436ff194bd9SJ. Bruce Fields rp->rp_buf = rp->rp_ibuf; 443758fb12e6SJeff Layton mutex_init(&rp->rp_mutex); 443858fb12e6SJeff Layton } 443958fb12e6SJeff Layton 444058fb12e6SJeff Layton static void nfsd4_cstate_assign_replay(struct nfsd4_compound_state *cstate, 444158fb12e6SJeff Layton struct nfs4_stateowner *so) 444258fb12e6SJeff Layton { 444358fb12e6SJeff Layton if (!nfsd4_has_session(cstate)) { 444458fb12e6SJeff Layton mutex_lock(&so->so_replay.rp_mutex); 4445b5971afaSKinglong Mee cstate->replay_owner = nfs4_get_stateowner(so); 444658fb12e6SJeff Layton } 444758fb12e6SJeff Layton } 444858fb12e6SJeff Layton 444958fb12e6SJeff Layton void nfsd4_cstate_clear_replay(struct nfsd4_compound_state *cstate) 445058fb12e6SJeff Layton { 445158fb12e6SJeff Layton struct nfs4_stateowner *so = cstate->replay_owner; 445258fb12e6SJeff Layton 445358fb12e6SJeff Layton if (so != NULL) { 445458fb12e6SJeff Layton cstate->replay_owner = NULL; 445558fb12e6SJeff Layton mutex_unlock(&so->so_replay.rp_mutex); 445658fb12e6SJeff Layton nfs4_put_stateowner(so); 445758fb12e6SJeff Layton } 4458ff194bd9SJ. Bruce Fields } 4459ff194bd9SJ. Bruce Fields 4460fe0750e5SJ. Bruce Fields static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) 44611da177e4SLinus Torvalds { 44621da177e4SLinus Torvalds struct nfs4_stateowner *sop; 44631da177e4SLinus Torvalds 4464fe0750e5SJ. Bruce Fields sop = kmem_cache_alloc(slab, GFP_KERNEL); 4465ff194bd9SJ. Bruce Fields if (!sop) 4466ff194bd9SJ. Bruce Fields return NULL; 4467ff194bd9SJ. Bruce Fields 44686f4859b8SJ. Bruce Fields xdr_netobj_dup(&sop->so_owner, owner, GFP_KERNEL); 4469ff194bd9SJ. Bruce Fields if (!sop->so_owner.data) { 4470fe0750e5SJ. Bruce Fields kmem_cache_free(slab, sop); 4471ff194bd9SJ. Bruce Fields return NULL; 4472ff194bd9SJ. Bruce Fields } 4473ff194bd9SJ. Bruce Fields 4474ff194bd9SJ. Bruce Fields INIT_LIST_HEAD(&sop->so_stateids); 4475ff194bd9SJ. Bruce Fields sop->so_client = clp; 4476ff194bd9SJ. Bruce Fields init_nfs4_replay(&sop->so_replay); 44776b180f0bSJeff Layton atomic_set(&sop->so_count, 1); 44781da177e4SLinus Torvalds return sop; 44791da177e4SLinus Torvalds } 4480ff194bd9SJ. Bruce Fields 4481fe0750e5SJ. Bruce Fields static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) 4482ff194bd9SJ. Bruce Fields { 4483d4f0489fSTrond Myklebust lockdep_assert_held(&clp->cl_lock); 44849b531137SStanislav Kinsbursky 4485d4f0489fSTrond Myklebust list_add(&oo->oo_owner.so_strhash, 4486d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 4487fe0750e5SJ. Bruce Fields list_add(&oo->oo_perclient, &clp->cl_openowners); 44881da177e4SLinus Torvalds } 44891da177e4SLinus Torvalds 44908f4b54c5SJeff Layton static void nfs4_unhash_openowner(struct nfs4_stateowner *so) 44918f4b54c5SJeff Layton { 4492d4f0489fSTrond Myklebust unhash_openowner_locked(openowner(so)); 44938f4b54c5SJeff Layton } 44948f4b54c5SJeff Layton 44956b180f0bSJeff Layton static void nfs4_free_openowner(struct nfs4_stateowner *so) 44966b180f0bSJeff Layton { 44976b180f0bSJeff Layton struct nfs4_openowner *oo = openowner(so); 44986b180f0bSJeff Layton 44996b180f0bSJeff Layton kmem_cache_free(openowner_slab, oo); 45006b180f0bSJeff Layton } 45016b180f0bSJeff Layton 45026b180f0bSJeff Layton static const struct nfs4_stateowner_operations openowner_ops = { 45038f4b54c5SJeff Layton .so_unhash = nfs4_unhash_openowner, 45046b180f0bSJeff Layton .so_free = nfs4_free_openowner, 45056b180f0bSJeff Layton }; 45066b180f0bSJeff Layton 45077fc0564eSAndrew Elble static struct nfs4_ol_stateid * 45087fc0564eSAndrew Elble nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 45097fc0564eSAndrew Elble { 45107fc0564eSAndrew Elble struct nfs4_ol_stateid *local, *ret = NULL; 45117fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 45127fc0564eSAndrew Elble 45137fc0564eSAndrew Elble lockdep_assert_held(&fp->fi_lock); 45147fc0564eSAndrew Elble 45157fc0564eSAndrew Elble list_for_each_entry(local, &fp->fi_stateids, st_perfile) { 45167fc0564eSAndrew Elble /* ignore lock owners */ 45177fc0564eSAndrew Elble if (local->st_stateowner->so_is_open_owner == 0) 45187fc0564eSAndrew Elble continue; 451915ca08d3STrond Myklebust if (local->st_stateowner != &oo->oo_owner) 452015ca08d3STrond Myklebust continue; 452115ca08d3STrond Myklebust if (local->st_stid.sc_type == NFS4_OPEN_STID) { 45227fc0564eSAndrew Elble ret = local; 4523a15dfcd5SElena Reshetova refcount_inc(&ret->st_stid.sc_count); 45247fc0564eSAndrew Elble break; 45257fc0564eSAndrew Elble } 45267fc0564eSAndrew Elble } 45277fc0564eSAndrew Elble return ret; 45287fc0564eSAndrew Elble } 45297fc0564eSAndrew Elble 453015ca08d3STrond Myklebust static __be32 453115ca08d3STrond Myklebust nfsd4_verify_open_stid(struct nfs4_stid *s) 453215ca08d3STrond Myklebust { 453315ca08d3STrond Myklebust __be32 ret = nfs_ok; 453415ca08d3STrond Myklebust 453515ca08d3STrond Myklebust switch (s->sc_type) { 453615ca08d3STrond Myklebust default: 453715ca08d3STrond Myklebust break; 45384f176417STrond Myklebust case 0: 453915ca08d3STrond Myklebust case NFS4_CLOSED_STID: 454015ca08d3STrond Myklebust case NFS4_CLOSED_DELEG_STID: 454115ca08d3STrond Myklebust ret = nfserr_bad_stateid; 454215ca08d3STrond Myklebust break; 454315ca08d3STrond Myklebust case NFS4_REVOKED_DELEG_STID: 454415ca08d3STrond Myklebust ret = nfserr_deleg_revoked; 454515ca08d3STrond Myklebust } 454615ca08d3STrond Myklebust return ret; 454715ca08d3STrond Myklebust } 454815ca08d3STrond Myklebust 454915ca08d3STrond Myklebust /* Lock the stateid st_mutex, and deal with races with CLOSE */ 455015ca08d3STrond Myklebust static __be32 455115ca08d3STrond Myklebust nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp) 455215ca08d3STrond Myklebust { 455315ca08d3STrond Myklebust __be32 ret; 455415ca08d3STrond Myklebust 45554f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX); 455615ca08d3STrond Myklebust ret = nfsd4_verify_open_stid(&stp->st_stid); 455715ca08d3STrond Myklebust if (ret != nfs_ok) 455815ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 455915ca08d3STrond Myklebust return ret; 456015ca08d3STrond Myklebust } 456115ca08d3STrond Myklebust 456215ca08d3STrond Myklebust static struct nfs4_ol_stateid * 456315ca08d3STrond Myklebust nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open) 456415ca08d3STrond Myklebust { 456515ca08d3STrond Myklebust struct nfs4_ol_stateid *stp; 456615ca08d3STrond Myklebust for (;;) { 456715ca08d3STrond Myklebust spin_lock(&fp->fi_lock); 456815ca08d3STrond Myklebust stp = nfsd4_find_existing_open(fp, open); 456915ca08d3STrond Myklebust spin_unlock(&fp->fi_lock); 457015ca08d3STrond Myklebust if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok) 457115ca08d3STrond Myklebust break; 457215ca08d3STrond Myklebust nfs4_put_stid(&stp->st_stid); 457315ca08d3STrond Myklebust } 457415ca08d3STrond Myklebust return stp; 457515ca08d3STrond Myklebust } 457615ca08d3STrond Myklebust 4577fe0750e5SJ. Bruce Fields static struct nfs4_openowner * 457813d6f66bSTrond Myklebust alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 4579db24b3b4SJeff Layton struct nfsd4_compound_state *cstate) 4580db24b3b4SJeff Layton { 458113d6f66bSTrond Myklebust struct nfs4_client *clp = cstate->clp; 45827ffb5880STrond Myklebust struct nfs4_openowner *oo, *ret; 45831da177e4SLinus Torvalds 4584fe0750e5SJ. Bruce Fields oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 4585fe0750e5SJ. Bruce Fields if (!oo) 45861da177e4SLinus Torvalds return NULL; 45876b180f0bSJeff Layton oo->oo_owner.so_ops = &openowner_ops; 4588fe0750e5SJ. Bruce Fields oo->oo_owner.so_is_open_owner = 1; 4589fe0750e5SJ. Bruce Fields oo->oo_owner.so_seqid = open->op_seqid; 4590d3134b10SJeff Layton oo->oo_flags = 0; 4591db24b3b4SJeff Layton if (nfsd4_has_session(cstate)) 4592db24b3b4SJeff Layton oo->oo_flags |= NFS4_OO_CONFIRMED; 4593fe0750e5SJ. Bruce Fields oo->oo_time = 0; 459438c387b5SJ. Bruce Fields oo->oo_last_closed_stid = NULL; 4595fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&oo->oo_close_lru); 4596d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 4597d4f0489fSTrond Myklebust ret = find_openstateowner_str_locked(strhashval, open, clp); 45987ffb5880STrond Myklebust if (ret == NULL) { 4599fe0750e5SJ. Bruce Fields hash_openowner(oo, clp, strhashval); 46007ffb5880STrond Myklebust ret = oo; 46017ffb5880STrond Myklebust } else 4602d50ffdedSKinglong Mee nfs4_free_stateowner(&oo->oo_owner); 4603d50ffdedSKinglong Mee 4604d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 4605c5952338SJeff Layton return ret; 46061da177e4SLinus Torvalds } 46071da177e4SLinus Torvalds 46087fc0564eSAndrew Elble static struct nfs4_ol_stateid * 46098c7245abSOleg Drokin init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open) 46107fc0564eSAndrew Elble { 46111da177e4SLinus Torvalds 46127fc0564eSAndrew Elble struct nfs4_openowner *oo = open->op_openowner; 46137fc0564eSAndrew Elble struct nfs4_ol_stateid *retstp = NULL; 46148c7245abSOleg Drokin struct nfs4_ol_stateid *stp; 46157fc0564eSAndrew Elble 46168c7245abSOleg Drokin stp = open->op_stp; 46175cc1fb2aSOleg Drokin /* We are moving these outside of the spinlocks to avoid the warnings */ 46185cc1fb2aSOleg Drokin mutex_init(&stp->st_mutex); 46194f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 46205cc1fb2aSOleg Drokin 462115ca08d3STrond Myklebust retry: 46227fc0564eSAndrew Elble spin_lock(&oo->oo_owner.so_client->cl_lock); 46237fc0564eSAndrew Elble spin_lock(&fp->fi_lock); 46247fc0564eSAndrew Elble 46257fc0564eSAndrew Elble retstp = nfsd4_find_existing_open(fp, open); 46267fc0564eSAndrew Elble if (retstp) 46277fc0564eSAndrew Elble goto out_unlock; 46288c7245abSOleg Drokin 46298c7245abSOleg Drokin open->op_stp = NULL; 4630a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 46313abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_OPEN_STID; 46323c87b9b7STrond Myklebust INIT_LIST_HEAD(&stp->st_locks); 4633b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&oo->oo_owner); 463413cd2184SNeilBrown get_nfs4_file(fp); 463511b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 46361da177e4SLinus Torvalds stp->st_access_bmap = 0; 46371da177e4SLinus Torvalds stp->st_deny_bmap = 0; 46384c4cd222SNeilBrown stp->st_openstp = NULL; 46391c755dc1SJeff Layton list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 46401d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 46417fc0564eSAndrew Elble 46427fc0564eSAndrew Elble out_unlock: 46431d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 46441c755dc1SJeff Layton spin_unlock(&oo->oo_owner.so_client->cl_lock); 46455cc1fb2aSOleg Drokin if (retstp) { 464615ca08d3STrond Myklebust /* Handle races with CLOSE */ 464715ca08d3STrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 464815ca08d3STrond Myklebust nfs4_put_stid(&retstp->st_stid); 464915ca08d3STrond Myklebust goto retry; 465015ca08d3STrond Myklebust } 46518c7245abSOleg Drokin /* To keep mutex tracking happy */ 46525cc1fb2aSOleg Drokin mutex_unlock(&stp->st_mutex); 46538c7245abSOleg Drokin stp = retstp; 46545cc1fb2aSOleg Drokin } 46558c7245abSOleg Drokin return stp; 46561da177e4SLinus Torvalds } 46571da177e4SLinus Torvalds 4658d3134b10SJeff Layton /* 4659d3134b10SJeff Layton * In the 4.0 case we need to keep the owners around a little while to handle 4660d3134b10SJeff Layton * CLOSE replay. We still do need to release any file access that is held by 4661d3134b10SJeff Layton * them before returning however. 4662d3134b10SJeff Layton */ 46631da177e4SLinus Torvalds static void 4664d3134b10SJeff Layton move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) 46651da177e4SLinus Torvalds { 4666217526e7SJeff Layton struct nfs4_ol_stateid *last; 4667d3134b10SJeff Layton struct nfs4_openowner *oo = openowner(s->st_stateowner); 4668d3134b10SJeff Layton struct nfsd_net *nn = net_generic(s->st_stid.sc_client->net, 4669d3134b10SJeff Layton nfsd_net_id); 467073758fedSStanislav Kinsbursky 4671fe0750e5SJ. Bruce Fields dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); 46721da177e4SLinus Torvalds 4673b401be22SJeff Layton /* 4674b401be22SJeff Layton * We know that we hold one reference via nfsd4_close, and another 4675b401be22SJeff Layton * "persistent" reference for the client. If the refcount is higher 4676b401be22SJeff Layton * than 2, then there are still calls in progress that are using this 4677b401be22SJeff Layton * stateid. We can't put the sc_file reference until they are finished. 4678b401be22SJeff Layton * Wait for the refcount to drop to 2. Since it has been unhashed, 4679b401be22SJeff Layton * there should be no danger of the refcount going back up again at 4680b401be22SJeff Layton * this point. 4681b401be22SJeff Layton */ 4682a15dfcd5SElena Reshetova wait_event(close_wq, refcount_read(&s->st_stid.sc_count) == 2); 4683b401be22SJeff Layton 4684d3134b10SJeff Layton release_all_access(s); 4685d3134b10SJeff Layton if (s->st_stid.sc_file) { 4686d3134b10SJeff Layton put_nfs4_file(s->st_stid.sc_file); 4687d3134b10SJeff Layton s->st_stid.sc_file = NULL; 4688d3134b10SJeff Layton } 4689217526e7SJeff Layton 4690217526e7SJeff Layton spin_lock(&nn->client_lock); 4691217526e7SJeff Layton last = oo->oo_last_closed_stid; 4692d3134b10SJeff Layton oo->oo_last_closed_stid = s; 469373758fedSStanislav Kinsbursky list_move_tail(&oo->oo_close_lru, &nn->close_lru); 469420b7d86fSArnd Bergmann oo->oo_time = ktime_get_boottime_seconds(); 4695217526e7SJeff Layton spin_unlock(&nn->client_lock); 4696217526e7SJeff Layton if (last) 4697217526e7SJeff Layton nfs4_put_stid(&last->st_stid); 46981da177e4SLinus Torvalds } 46991da177e4SLinus Torvalds 470015424748SChuck Lever static noinline_for_stack struct nfs4_file * 470115424748SChuck Lever nfsd4_file_hash_lookup(const struct svc_fh *fhp) 47021da177e4SLinus Torvalds { 4703d47b295eSChuck Lever struct inode *inode = d_inode(fhp->fh_dentry); 4704d47b295eSChuck Lever struct rhlist_head *tmp, *list; 470515424748SChuck Lever struct nfs4_file *fi; 47061da177e4SLinus Torvalds 47075b095e99SJeff Layton rcu_read_lock(); 4708d47b295eSChuck Lever list = rhltable_lookup(&nfs4_file_rhltable, &inode, 4709d47b295eSChuck Lever nfs4_file_rhash_params); 4710d47b295eSChuck Lever rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) { 471115424748SChuck Lever if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { 471215424748SChuck Lever if (refcount_inc_not_zero(&fi->fi_ref)) { 47135b095e99SJeff Layton rcu_read_unlock(); 471415424748SChuck Lever return fi; 4715950e0118STrond Myklebust } 4716950e0118STrond Myklebust } 471715424748SChuck Lever } 471815424748SChuck Lever rcu_read_unlock(); 4719950e0118STrond Myklebust return NULL; 4720950e0118STrond Myklebust } 4721950e0118STrond Myklebust 47229270fc51SChuck Lever /* 47239270fc51SChuck Lever * On hash insertion, identify entries with the same inode but 4724d47b295eSChuck Lever * distinct filehandles. They will all be on the list returned 4725d47b295eSChuck Lever * by rhltable_lookup(). 4726d47b295eSChuck Lever * 4727d47b295eSChuck Lever * inode->i_lock prevents racing insertions from adding an entry 4728d47b295eSChuck Lever * for the same inode/fhp pair twice. 47299270fc51SChuck Lever */ 47309270fc51SChuck Lever static noinline_for_stack struct nfs4_file * 47319270fc51SChuck Lever nfsd4_file_hash_insert(struct nfs4_file *new, const struct svc_fh *fhp) 4732950e0118STrond Myklebust { 4733d47b295eSChuck Lever struct inode *inode = d_inode(fhp->fh_dentry); 4734d47b295eSChuck Lever struct rhlist_head *tmp, *list; 4735950e0118STrond Myklebust struct nfs4_file *ret = NULL; 4736ca943217STrond Myklebust bool alias_found = false; 47379270fc51SChuck Lever struct nfs4_file *fi; 4738d47b295eSChuck Lever int err; 4739950e0118STrond Myklebust 4740d47b295eSChuck Lever rcu_read_lock(); 4741d47b295eSChuck Lever spin_lock(&inode->i_lock); 4742d47b295eSChuck Lever 4743d47b295eSChuck Lever list = rhltable_lookup(&nfs4_file_rhltable, &inode, 4744d47b295eSChuck Lever nfs4_file_rhash_params); 4745d47b295eSChuck Lever rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) { 47469270fc51SChuck Lever if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { 47479270fc51SChuck Lever if (refcount_inc_not_zero(&fi->fi_ref)) 47489270fc51SChuck Lever ret = fi; 4749d47b295eSChuck Lever } else 47509270fc51SChuck Lever fi->fi_aliased = alias_found = true; 47511da177e4SLinus Torvalds } 4752d47b295eSChuck Lever if (ret) 4753d47b295eSChuck Lever goto out_unlock; 4754d47b295eSChuck Lever 47559270fc51SChuck Lever nfsd4_file_init(fhp, new); 4756d47b295eSChuck Lever err = rhltable_insert(&nfs4_file_rhltable, &new->fi_rlist, 4757d47b295eSChuck Lever nfs4_file_rhash_params); 4758d47b295eSChuck Lever if (err) 4759d47b295eSChuck Lever goto out_unlock; 4760d47b295eSChuck Lever 47611da177e4SLinus Torvalds new->fi_aliased = alias_found; 4762cdc97505SBenny Halevy ret = new; 4763d47b295eSChuck Lever 4764d47b295eSChuck Lever out_unlock: 4765d47b295eSChuck Lever spin_unlock(&inode->i_lock); 4766d47b295eSChuck Lever rcu_read_unlock(); 476713cd2184SNeilBrown return ret; 4768cdc97505SBenny Halevy } 47691da177e4SLinus Torvalds 47703341678fSChuck Lever static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi) 4771950e0118STrond Myklebust { 4772d47b295eSChuck Lever rhltable_remove(&nfs4_file_rhltable, &fi->fi_rlist, 4773d47b295eSChuck Lever nfs4_file_rhash_params); 4774950e0118STrond Myklebust } 4775950e0118STrond Myklebust 47764f83aa30SJ. Bruce Fields /* 47771da177e4SLinus Torvalds * Called to check deny when READ with all zero stateid or 47781da177e4SLinus Torvalds * WRITE with all zero or all one stateid 47791da177e4SLinus Torvalds */ 4780b37ad28bSAl Viro static __be32 47811da177e4SLinus Torvalds nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) 47821da177e4SLinus Torvalds { 47831da177e4SLinus Torvalds struct nfs4_file *fp; 4784baeb4ff0SJeff Layton __be32 ret = nfs_ok; 47851da177e4SLinus Torvalds 478615424748SChuck Lever fp = nfsd4_file_hash_lookup(current_fh); 478713cd2184SNeilBrown if (!fp) 4788baeb4ff0SJeff Layton return ret; 478915424748SChuck Lever 4790baeb4ff0SJeff Layton /* Check for conflicting share reservations */ 47911d31a253STrond Myklebust spin_lock(&fp->fi_lock); 4792baeb4ff0SJeff Layton if (fp->fi_share_deny & deny_type) 4793baeb4ff0SJeff Layton ret = nfserr_locked; 47941d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 479513cd2184SNeilBrown put_nfs4_file(fp); 479613cd2184SNeilBrown return ret; 47971da177e4SLinus Torvalds } 47981da177e4SLinus Torvalds 4799c035362eSChuck Lever static bool nfsd4_deleg_present(const struct inode *inode) 4800c035362eSChuck Lever { 480177c67530SJeff Layton struct file_lock_context *ctx = locks_inode_context(inode); 4802c035362eSChuck Lever 4803c035362eSChuck Lever return ctx && !list_empty_careful(&ctx->flc_lease); 4804c035362eSChuck Lever } 4805c035362eSChuck Lever 4806c035362eSChuck Lever /** 4807c035362eSChuck Lever * nfsd_wait_for_delegreturn - wait for delegations to be returned 4808c035362eSChuck Lever * @rqstp: the RPC transaction being executed 4809c035362eSChuck Lever * @inode: in-core inode of the file being waited for 4810c035362eSChuck Lever * 4811c035362eSChuck Lever * The timeout prevents deadlock if all nfsd threads happen to be 4812c035362eSChuck Lever * tied up waiting for returning delegations. 4813c035362eSChuck Lever * 4814c035362eSChuck Lever * Return values: 4815c035362eSChuck Lever * %true: delegation was returned 4816c035362eSChuck Lever * %false: timed out waiting for delegreturn 4817c035362eSChuck Lever */ 4818c035362eSChuck Lever bool nfsd_wait_for_delegreturn(struct svc_rqst *rqstp, struct inode *inode) 4819c035362eSChuck Lever { 4820c035362eSChuck Lever long __maybe_unused timeo; 4821c035362eSChuck Lever 4822c035362eSChuck Lever timeo = wait_var_event_timeout(inode, !nfsd4_deleg_present(inode), 4823c035362eSChuck Lever NFSD_DELEGRETURN_TIMEOUT); 4824c035362eSChuck Lever trace_nfsd_delegret_wakeup(rqstp, inode, timeo); 4825c035362eSChuck Lever return timeo > 0; 4826c035362eSChuck Lever } 4827c035362eSChuck Lever 48280162ac2bSChristoph Hellwig static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) 48291da177e4SLinus Torvalds { 48300162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 483111b9164aSTrond Myklebust struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 483211b9164aSTrond Myklebust nfsd_net_id); 4833e8c69d17SJ. Bruce Fields 483411b9164aSTrond Myklebust block_delegations(&dp->dl_stid.sc_file->fi_fhandle); 4835f54fe962SJeff Layton 483602e1215fSJeff Layton /* 483702e1215fSJeff Layton * We can't do this in nfsd_break_deleg_cb because it is 4838f54fe962SJeff Layton * already holding inode->i_lock. 4839f54fe962SJeff Layton * 4840dff1399fSJeff Layton * If the dl_time != 0, then we know that it has already been 4841dff1399fSJeff Layton * queued for a lease break. Don't queue it again. 4842dff1399fSJeff Layton */ 4843f54fe962SJeff Layton spin_lock(&state_lock); 4844548ec080SJ. Bruce Fields if (delegation_hashed(dp) && dp->dl_time == 0) { 484520b7d86fSArnd Bergmann dp->dl_time = ktime_get_boottime_seconds(); 484602e1215fSJeff Layton list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 484702e1215fSJeff Layton } 484802e1215fSJeff Layton spin_unlock(&state_lock); 4849dff1399fSJeff Layton } 48501da177e4SLinus Torvalds 48510162ac2bSChristoph Hellwig static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, 48520162ac2bSChristoph Hellwig struct rpc_task *task) 48530162ac2bSChristoph Hellwig { 48540162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 48550162ac2bSChristoph Hellwig 48561035d654SChuck Lever trace_nfsd_cb_recall_done(&dp->dl_stid.sc_stateid, task); 48571035d654SChuck Lever 485812ed22f3SJ. Bruce Fields if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID || 485912ed22f3SJ. Bruce Fields dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) 4860a457974fSAndrew Elble return 1; 4861a457974fSAndrew Elble 48620162ac2bSChristoph Hellwig switch (task->tk_status) { 48630162ac2bSChristoph Hellwig case 0: 48640162ac2bSChristoph Hellwig return 1; 48651c73b9d2SScott Mayhew case -NFS4ERR_DELAY: 48661c73b9d2SScott Mayhew rpc_delay(task, 2 * HZ); 48671c73b9d2SScott Mayhew return 0; 48680162ac2bSChristoph Hellwig case -EBADHANDLE: 48690162ac2bSChristoph Hellwig case -NFS4ERR_BAD_STATEID: 48700162ac2bSChristoph Hellwig /* 48710162ac2bSChristoph Hellwig * Race: client probably got cb_recall before open reply 48720162ac2bSChristoph Hellwig * granting delegation. 48730162ac2bSChristoph Hellwig */ 48740162ac2bSChristoph Hellwig if (dp->dl_retries--) { 48750162ac2bSChristoph Hellwig rpc_delay(task, 2 * HZ); 48760162ac2bSChristoph Hellwig return 0; 48770162ac2bSChristoph Hellwig } 4878df561f66SGustavo A. R. Silva fallthrough; 48790162ac2bSChristoph Hellwig default: 48801c73b9d2SScott Mayhew return 1; 48810162ac2bSChristoph Hellwig } 48820162ac2bSChristoph Hellwig } 48830162ac2bSChristoph Hellwig 48840162ac2bSChristoph Hellwig static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) 48850162ac2bSChristoph Hellwig { 48860162ac2bSChristoph Hellwig struct nfs4_delegation *dp = cb_to_delegation(cb); 48870162ac2bSChristoph Hellwig 48880162ac2bSChristoph Hellwig nfs4_put_stid(&dp->dl_stid); 48890162ac2bSChristoph Hellwig } 48900162ac2bSChristoph Hellwig 4891c4cb8974SJulia Lawall static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = { 48920162ac2bSChristoph Hellwig .prepare = nfsd4_cb_recall_prepare, 48930162ac2bSChristoph Hellwig .done = nfsd4_cb_recall_done, 48940162ac2bSChristoph Hellwig .release = nfsd4_cb_recall_release, 48950162ac2bSChristoph Hellwig }; 48960162ac2bSChristoph Hellwig 489702e1215fSJeff Layton static void nfsd_break_one_deleg(struct nfs4_delegation *dp) 489802e1215fSJeff Layton { 489902e1215fSJeff Layton /* 490002e1215fSJeff Layton * We're assuming the state code never drops its reference 490102e1215fSJeff Layton * without first removing the lease. Since we're in this lease 49024a269efbSJ. Bruce Fields * callback (and since the lease code is serialized by the 490325fbe1fcSJeff Layton * flc_lock) we know the server hasn't removed the lease yet, and 49044a269efbSJ. Bruce Fields * we know it's safe to take a reference. 490502e1215fSJeff Layton */ 4906a15dfcd5SElena Reshetova refcount_inc(&dp->dl_stid.sc_count); 4907b95239caSJeff Layton WARN_ON_ONCE(!nfsd4_run_cb(&dp->dl_recall)); 49086b57d9c8SJ. Bruce Fields } 49096b57d9c8SJ. Bruce Fields 491025fbe1fcSJeff Layton /* Called from break_lease() with flc_lock held. */ 49114d01b7f5SJeff Layton static bool 49124d01b7f5SJeff Layton nfsd_break_deleg_cb(struct file_lock *fl) 49136b57d9c8SJ. Bruce Fields { 4914653e514eSJ. Bruce Fields struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; 4915653e514eSJ. Bruce Fields struct nfs4_file *fp = dp->dl_stid.sc_file; 491666af2579SDai Ngo struct nfs4_client *clp = dp->dl_stid.sc_client; 491766af2579SDai Ngo struct nfsd_net *nn; 49186b57d9c8SJ. Bruce Fields 491917d76ddfSChuck Lever trace_nfsd_cb_recall(&dp->dl_stid); 4920dd5e3fbcSChuck Lever 492166af2579SDai Ngo dp->dl_recalled = true; 492266af2579SDai Ngo atomic_inc(&clp->cl_delegs_in_recall); 492366af2579SDai Ngo if (try_to_expire_client(clp)) { 492466af2579SDai Ngo nn = net_generic(clp->net, nfsd_net_id); 492566af2579SDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 492666af2579SDai Ngo } 492766af2579SDai Ngo 49280272e1fdSJ. Bruce Fields /* 49290272e1fdSJ. Bruce Fields * We don't want the locks code to timeout the lease for us; 4930acfdf5c3SJ. Bruce Fields * we'll remove it ourself if a delegation isn't returned 49316b57d9c8SJ. Bruce Fields * in time: 49320272e1fdSJ. Bruce Fields */ 49330272e1fdSJ. Bruce Fields fl->fl_break_time = 0; 49341da177e4SLinus Torvalds 493502e1215fSJeff Layton spin_lock(&fp->fi_lock); 4936417c6629SJeff Layton fp->fi_had_conflict = true; 49375d926e8cSJ. Bruce Fields nfsd_break_one_deleg(dp); 493802e1215fSJeff Layton spin_unlock(&fp->fi_lock); 4939b95239caSJeff Layton return false; 49401da177e4SLinus Torvalds } 49411da177e4SLinus Torvalds 494250719bf3SChuck Lever /** 494350719bf3SChuck Lever * nfsd_breaker_owns_lease - Check if lease conflict was resolved 494450719bf3SChuck Lever * @fl: Lock state to check 494550719bf3SChuck Lever * 494650719bf3SChuck Lever * Return values: 494750719bf3SChuck Lever * %true: Lease conflict was resolved 494850719bf3SChuck Lever * %false: Lease conflict was not resolved. 494950719bf3SChuck Lever */ 495028df3d15SJ. Bruce Fields static bool nfsd_breaker_owns_lease(struct file_lock *fl) 495128df3d15SJ. Bruce Fields { 495228df3d15SJ. Bruce Fields struct nfs4_delegation *dl = fl->fl_owner; 495328df3d15SJ. Bruce Fields struct svc_rqst *rqst; 495428df3d15SJ. Bruce Fields struct nfs4_client *clp; 495528df3d15SJ. Bruce Fields 495628df3d15SJ. Bruce Fields if (!i_am_nfsd()) 495750719bf3SChuck Lever return false; 495828df3d15SJ. Bruce Fields rqst = kthread_data(current); 495913956160SJ. Bruce Fields /* Note rq_prog == NFS_ACL_PROGRAM is also possible: */ 496013956160SJ. Bruce Fields if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4) 496150719bf3SChuck Lever return false; 496228df3d15SJ. Bruce Fields clp = *(rqst->rq_lease_breaker); 496328df3d15SJ. Bruce Fields return dl->dl_stid.sc_client == clp; 496428df3d15SJ. Bruce Fields } 496528df3d15SJ. Bruce Fields 4966c45198edSJeff Layton static int 49677448cc37SJeff Layton nfsd_change_deleg_cb(struct file_lock *onlist, int arg, 49687448cc37SJeff Layton struct list_head *dispose) 49691da177e4SLinus Torvalds { 497066af2579SDai Ngo struct nfs4_delegation *dp = (struct nfs4_delegation *)onlist->fl_owner; 497166af2579SDai Ngo struct nfs4_client *clp = dp->dl_stid.sc_client; 497266af2579SDai Ngo 497366af2579SDai Ngo if (arg & F_UNLCK) { 497466af2579SDai Ngo if (dp->dl_recalled) 497566af2579SDai Ngo atomic_dec(&clp->cl_delegs_in_recall); 4976c45198edSJeff Layton return lease_modify(onlist, arg, dispose); 497766af2579SDai Ngo } else 49781da177e4SLinus Torvalds return -EAGAIN; 49791da177e4SLinus Torvalds } 49801da177e4SLinus Torvalds 49817b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_lease_mng_ops = { 498228df3d15SJ. Bruce Fields .lm_breaker_owns_lease = nfsd_breaker_owns_lease, 49838fb47a4fSJ. Bruce Fields .lm_break = nfsd_break_deleg_cb, 49848fb47a4fSJ. Bruce Fields .lm_change = nfsd_change_deleg_cb, 49851da177e4SLinus Torvalds }; 49861da177e4SLinus Torvalds 49877a8711c9SJ. Bruce Fields static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) 49887a8711c9SJ. Bruce Fields { 49897a8711c9SJ. Bruce Fields if (nfsd4_has_session(cstate)) 49907a8711c9SJ. Bruce Fields return nfs_ok; 49917a8711c9SJ. Bruce Fields if (seqid == so->so_seqid - 1) 49927a8711c9SJ. Bruce Fields return nfserr_replay_me; 49937a8711c9SJ. Bruce Fields if (seqid == so->so_seqid) 49947a8711c9SJ. Bruce Fields return nfs_ok; 49957a8711c9SJ. Bruce Fields return nfserr_bad_seqid; 49967a8711c9SJ. Bruce Fields } 49971da177e4SLinus Torvalds 49987950b531SJ. Bruce Fields static struct nfs4_client *lookup_clientid(clientid_t *clid, bool sessions, 49997950b531SJ. Bruce Fields struct nfsd_net *nn) 50007950b531SJ. Bruce Fields { 50017950b531SJ. Bruce Fields struct nfs4_client *found; 50027950b531SJ. Bruce Fields 50037950b531SJ. Bruce Fields spin_lock(&nn->client_lock); 50047950b531SJ. Bruce Fields found = find_confirmed_client(clid, sessions, nn); 50057950b531SJ. Bruce Fields if (found) 50067950b531SJ. Bruce Fields atomic_inc(&found->cl_rpc_users); 50077950b531SJ. Bruce Fields spin_unlock(&nn->client_lock); 50087950b531SJ. Bruce Fields return found; 50097950b531SJ. Bruce Fields } 50107950b531SJ. Bruce Fields 5011460d2709SJ. Bruce Fields static __be32 set_client(clientid_t *clid, 50124b24ca7dSJeff Layton struct nfsd4_compound_state *cstate, 5013f71475baSJ. Bruce Fields struct nfsd_net *nn) 50144b24ca7dSJeff Layton { 50154b24ca7dSJeff Layton if (cstate->clp) { 50167950b531SJ. Bruce Fields if (!same_clid(&cstate->clp->cl_clientid, clid)) 50174b24ca7dSJeff Layton return nfserr_stale_clientid; 50184b24ca7dSJeff Layton return nfs_ok; 50194b24ca7dSJeff Layton } 50204b24ca7dSJeff Layton if (STALE_CLIENTID(clid, nn)) 50214b24ca7dSJeff Layton return nfserr_stale_clientid; 50224b24ca7dSJeff Layton /* 5023f71475baSJ. Bruce Fields * We're in the 4.0 case (otherwise the SEQUENCE op would have 5024f71475baSJ. Bruce Fields * set cstate->clp), so session = false: 50254b24ca7dSJeff Layton */ 5026f71475baSJ. Bruce Fields cstate->clp = lookup_clientid(clid, false, nn); 50277950b531SJ. Bruce Fields if (!cstate->clp) 50284b24ca7dSJeff Layton return nfserr_expired; 50294b24ca7dSJeff Layton return nfs_ok; 50304b24ca7dSJeff Layton } 50314b24ca7dSJeff Layton 5032b37ad28bSAl Viro __be32 50336668958fSAndy Adamson nfsd4_process_open1(struct nfsd4_compound_state *cstate, 50343320fef1SStanislav Kinsbursky struct nfsd4_open *open, struct nfsd_net *nn) 50351da177e4SLinus Torvalds { 50361da177e4SLinus Torvalds clientid_t *clientid = &open->op_clientid; 50371da177e4SLinus Torvalds struct nfs4_client *clp = NULL; 50381da177e4SLinus Torvalds unsigned int strhashval; 5039fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo = NULL; 50404cdc951bSJ. Bruce Fields __be32 status; 50411da177e4SLinus Torvalds 504232513b40SJ. Bruce Fields /* 504332513b40SJ. Bruce Fields * In case we need it later, after we've already created the 504432513b40SJ. Bruce Fields * file and don't want to risk a further failure: 504532513b40SJ. Bruce Fields */ 504632513b40SJ. Bruce Fields open->op_file = nfsd4_alloc_file(); 504732513b40SJ. Bruce Fields if (open->op_file == NULL) 504832513b40SJ. Bruce Fields return nfserr_jukebox; 50491da177e4SLinus Torvalds 5050f71475baSJ. Bruce Fields status = set_client(clientid, cstate, nn); 505113d6f66bSTrond Myklebust if (status) 505213d6f66bSTrond Myklebust return status; 505313d6f66bSTrond Myklebust clp = cstate->clp; 50542d91e895STrond Myklebust 5055d4f0489fSTrond Myklebust strhashval = ownerstr_hashval(&open->op_owner); 5056d4f0489fSTrond Myklebust oo = find_openstateowner_str(strhashval, open, clp); 50572d91e895STrond Myklebust open->op_openowner = oo; 50582d91e895STrond Myklebust if (!oo) { 5059bcf130f9SJ. Bruce Fields goto new_owner; 50600f442aa2SJ. Bruce Fields } 5061dad1c067SJ. Bruce Fields if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 50620f442aa2SJ. Bruce Fields /* Replace unconfirmed owners without checking for replay. */ 5063fe0750e5SJ. Bruce Fields release_openowner(oo); 5064fe0750e5SJ. Bruce Fields open->op_openowner = NULL; 5065bcf130f9SJ. Bruce Fields goto new_owner; 50660f442aa2SJ. Bruce Fields } 50674cdc951bSJ. Bruce Fields status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); 50684cdc951bSJ. Bruce Fields if (status) 50694cdc951bSJ. Bruce Fields return status; 50704cdc951bSJ. Bruce Fields goto alloc_stateid; 5071bcf130f9SJ. Bruce Fields new_owner: 507213d6f66bSTrond Myklebust oo = alloc_init_open_stateowner(strhashval, open, cstate); 5073fe0750e5SJ. Bruce Fields if (oo == NULL) 50743e772463SJ. Bruce Fields return nfserr_jukebox; 5075fe0750e5SJ. Bruce Fields open->op_openowner = oo; 50764cdc951bSJ. Bruce Fields alloc_stateid: 5077b49e084dSJeff Layton open->op_stp = nfs4_alloc_open_stateid(clp); 50784cdc951bSJ. Bruce Fields if (!open->op_stp) 50794cdc951bSJ. Bruce Fields return nfserr_jukebox; 50808287f009SSachin Bhamare 50818287f009SSachin Bhamare if (nfsd4_has_session(cstate) && 50828287f009SSachin Bhamare (cstate->current_fh.fh_export->ex_flags & NFSEXP_PNFS)) { 50838287f009SSachin Bhamare open->op_odstate = alloc_clnt_odstate(clp); 50848287f009SSachin Bhamare if (!open->op_odstate) 50858287f009SSachin Bhamare return nfserr_jukebox; 50868287f009SSachin Bhamare } 50878287f009SSachin Bhamare 50880f442aa2SJ. Bruce Fields return nfs_ok; 50891da177e4SLinus Torvalds } 50901da177e4SLinus Torvalds 5091b37ad28bSAl Viro static inline __be32 50924a6e43e6SNeilBrown nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) 50934a6e43e6SNeilBrown { 50944a6e43e6SNeilBrown if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) 50954a6e43e6SNeilBrown return nfserr_openmode; 50964a6e43e6SNeilBrown else 50974a6e43e6SNeilBrown return nfs_ok; 50984a6e43e6SNeilBrown } 50994a6e43e6SNeilBrown 5100c47d832bSDaniel Mack static int share_access_to_flags(u32 share_access) 510124a0111eSJ. Bruce Fields { 510224a0111eSJ. Bruce Fields return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; 510324a0111eSJ. Bruce Fields } 510424a0111eSJ. Bruce Fields 510538c2f4b1SJ. Bruce Fields static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) 5106f459e453SJ. Bruce Fields { 5107f459e453SJ. Bruce Fields struct nfs4_stid *ret; 5108f459e453SJ. Bruce Fields 510995da1b3aSAndrew Elble ret = find_stateid_by_type(cl, s, 511095da1b3aSAndrew Elble NFS4_DELEG_STID|NFS4_REVOKED_DELEG_STID); 5111f459e453SJ. Bruce Fields if (!ret) 5112f459e453SJ. Bruce Fields return NULL; 5113f459e453SJ. Bruce Fields return delegstateid(ret); 5114f459e453SJ. Bruce Fields } 5115f459e453SJ. Bruce Fields 51168b289b2cSJ. Bruce Fields static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) 51178b289b2cSJ. Bruce Fields { 51188b289b2cSJ. Bruce Fields return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || 51198b289b2cSJ. Bruce Fields open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; 51208b289b2cSJ. Bruce Fields } 51218b289b2cSJ. Bruce Fields 5122b37ad28bSAl Viro static __be32 512341d22663SJ. Bruce Fields nfs4_check_deleg(struct nfs4_client *cl, struct nfsd4_open *open, 5124567d9829SNeilBrown struct nfs4_delegation **dp) 5125567d9829SNeilBrown { 5126567d9829SNeilBrown int flags; 5127b37ad28bSAl Viro __be32 status = nfserr_bad_stateid; 5128dcd94cc2STrond Myklebust struct nfs4_delegation *deleg; 5129567d9829SNeilBrown 5130dcd94cc2STrond Myklebust deleg = find_deleg_stateid(cl, &open->op_delegate_stateid); 5131dcd94cc2STrond Myklebust if (deleg == NULL) 5132c44c5eebSNeilBrown goto out; 513395da1b3aSAndrew Elble if (deleg->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) { 513495da1b3aSAndrew Elble nfs4_put_stid(&deleg->dl_stid); 513595da1b3aSAndrew Elble if (cl->cl_minorversion) 513695da1b3aSAndrew Elble status = nfserr_deleg_revoked; 513795da1b3aSAndrew Elble goto out; 513895da1b3aSAndrew Elble } 513924a0111eSJ. Bruce Fields flags = share_access_to_flags(open->op_share_access); 5140dcd94cc2STrond Myklebust status = nfs4_check_delegmode(deleg, flags); 5141dcd94cc2STrond Myklebust if (status) { 5142dcd94cc2STrond Myklebust nfs4_put_stid(&deleg->dl_stid); 5143dcd94cc2STrond Myklebust goto out; 5144dcd94cc2STrond Myklebust } 5145dcd94cc2STrond Myklebust *dp = deleg; 5146c44c5eebSNeilBrown out: 51478b289b2cSJ. Bruce Fields if (!nfsd4_is_deleg_cur(open)) 5148c44c5eebSNeilBrown return nfs_ok; 5149c44c5eebSNeilBrown if (status) 5150c44c5eebSNeilBrown return status; 5151dad1c067SJ. Bruce Fields open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 5152c44c5eebSNeilBrown return nfs_ok; 5153567d9829SNeilBrown } 5154567d9829SNeilBrown 515521fb4016SJ. Bruce Fields static inline int nfs4_access_to_access(u32 nfs4_access) 515621fb4016SJ. Bruce Fields { 515721fb4016SJ. Bruce Fields int flags = 0; 515821fb4016SJ. Bruce Fields 515921fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_READ) 516021fb4016SJ. Bruce Fields flags |= NFSD_MAY_READ; 516121fb4016SJ. Bruce Fields if (nfs4_access & NFS4_SHARE_ACCESS_WRITE) 516221fb4016SJ. Bruce Fields flags |= NFSD_MAY_WRITE; 516321fb4016SJ. Bruce Fields return flags; 516421fb4016SJ. Bruce Fields } 516521fb4016SJ. Bruce Fields 5166b37ad28bSAl Viro static inline __be32 51671da177e4SLinus Torvalds nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, 51681da177e4SLinus Torvalds struct nfsd4_open *open) 51691da177e4SLinus Torvalds { 51701da177e4SLinus Torvalds struct iattr iattr = { 51711da177e4SLinus Torvalds .ia_valid = ATTR_SIZE, 51721da177e4SLinus Torvalds .ia_size = 0, 51731da177e4SLinus Torvalds }; 51747fe2a71dSNeilBrown struct nfsd_attrs attrs = { 51757fe2a71dSNeilBrown .na_iattr = &iattr, 51767fe2a71dSNeilBrown }; 51771da177e4SLinus Torvalds if (!open->op_truncate) 51781da177e4SLinus Torvalds return 0; 51791da177e4SLinus Torvalds if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) 51809246585aSAl Viro return nfserr_inval; 51817fe2a71dSNeilBrown return nfsd_setattr(rqstp, fh, &attrs, 0, (time64_t)0); 51821da177e4SLinus Torvalds } 51831da177e4SLinus Torvalds 51847e6a72e5SChristoph Hellwig static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, 51856eb3a1d0SJeff Layton struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 51863d694271SDai Ngo struct nfsd4_open *open, bool new_stp) 51877e6a72e5SChristoph Hellwig { 5188fd4f83fdSJeff Layton struct nfsd_file *nf = NULL; 51897e6a72e5SChristoph Hellwig __be32 status; 51907e6a72e5SChristoph Hellwig int oflag = nfs4_access_to_omode(open->op_share_access); 51917e6a72e5SChristoph Hellwig int access = nfs4_access_to_access(open->op_share_access); 5192baeb4ff0SJeff Layton unsigned char old_access_bmap, old_deny_bmap; 51937e6a72e5SChristoph Hellwig 5194de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 5195baeb4ff0SJeff Layton 5196baeb4ff0SJeff Layton /* 5197baeb4ff0SJeff Layton * Are we trying to set a deny mode that would conflict with 5198baeb4ff0SJeff Layton * current access? 5199baeb4ff0SJeff Layton */ 5200baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 5201baeb4ff0SJeff Layton if (status != nfs_ok) { 52023d694271SDai Ngo if (status != nfserr_share_denied) { 52033d694271SDai Ngo spin_unlock(&fp->fi_lock); 52043d694271SDai Ngo goto out; 52053d694271SDai Ngo } 52063d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, 52073d694271SDai Ngo stp, open->op_share_deny, false)) 52083d694271SDai Ngo status = nfserr_jukebox; 5209baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 5210baeb4ff0SJeff Layton goto out; 5211baeb4ff0SJeff Layton } 5212baeb4ff0SJeff Layton 5213baeb4ff0SJeff Layton /* set access to the file */ 5214baeb4ff0SJeff Layton status = nfs4_file_get_access(fp, open->op_share_access); 5215baeb4ff0SJeff Layton if (status != nfs_ok) { 52163d694271SDai Ngo if (status != nfserr_share_denied) { 52173d694271SDai Ngo spin_unlock(&fp->fi_lock); 52183d694271SDai Ngo goto out; 52193d694271SDai Ngo } 52203d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, 52213d694271SDai Ngo stp, open->op_share_access, true)) 52223d694271SDai Ngo status = nfserr_jukebox; 5223baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 5224baeb4ff0SJeff Layton goto out; 5225baeb4ff0SJeff Layton } 5226baeb4ff0SJeff Layton 5227baeb4ff0SJeff Layton /* Set access bits in stateid */ 5228baeb4ff0SJeff Layton old_access_bmap = stp->st_access_bmap; 5229baeb4ff0SJeff Layton set_access(open->op_share_access, stp); 5230baeb4ff0SJeff Layton 5231baeb4ff0SJeff Layton /* Set new deny mask */ 5232baeb4ff0SJeff Layton old_deny_bmap = stp->st_deny_bmap; 5233baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 5234baeb4ff0SJeff Layton fp->fi_share_deny |= (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 5235baeb4ff0SJeff Layton 52367e6a72e5SChristoph Hellwig if (!fp->fi_fds[oflag]) { 5237de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 5238fb70bf12SChuck Lever 52390b3a551fSJeff Layton status = nfsd_file_acquire_opened(rqstp, cur_fh, access, 52400b3a551fSJeff Layton open->op_filp, &nf); 5241fb70bf12SChuck Lever if (status != nfs_ok) 5242baeb4ff0SJeff Layton goto out_put_access; 5243fb70bf12SChuck Lever 5244de18643dSTrond Myklebust spin_lock(&fp->fi_lock); 5245de18643dSTrond Myklebust if (!fp->fi_fds[oflag]) { 5246fd4f83fdSJeff Layton fp->fi_fds[oflag] = nf; 5247fd4f83fdSJeff Layton nf = NULL; 5248de18643dSTrond Myklebust } 52497e6a72e5SChristoph Hellwig } 5250de18643dSTrond Myklebust spin_unlock(&fp->fi_lock); 5251fd4f83fdSJeff Layton if (nf) 5252fd4f83fdSJeff Layton nfsd_file_put(nf); 52537e6a72e5SChristoph Hellwig 5254217fd6f6SJ. Bruce Fields status = nfserrno(nfsd_open_break_lease(cur_fh->fh_dentry->d_inode, 5255217fd6f6SJ. Bruce Fields access)); 5256217fd6f6SJ. Bruce Fields if (status) 5257217fd6f6SJ. Bruce Fields goto out_put_access; 5258217fd6f6SJ. Bruce Fields 52597e6a72e5SChristoph Hellwig status = nfsd4_truncate(rqstp, cur_fh, open); 52607e6a72e5SChristoph Hellwig if (status) 52617e6a72e5SChristoph Hellwig goto out_put_access; 52627e6a72e5SChristoph Hellwig out: 52637e6a72e5SChristoph Hellwig return status; 5264baeb4ff0SJeff Layton out_put_access: 5265baeb4ff0SJeff Layton stp->st_access_bmap = old_access_bmap; 5266baeb4ff0SJeff Layton nfs4_file_put_access(fp, open->op_share_access); 5267baeb4ff0SJeff Layton reset_union_bmap_deny(bmap_to_share_mode(old_deny_bmap), stp); 5268baeb4ff0SJeff Layton goto out; 52697e6a72e5SChristoph Hellwig } 52707e6a72e5SChristoph Hellwig 5271b37ad28bSAl Viro static __be32 52723d694271SDai Ngo nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, 52733d694271SDai Ngo struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, 52743d694271SDai Ngo struct nfsd4_open *open) 52751da177e4SLinus Torvalds { 5276b37ad28bSAl Viro __be32 status; 52776ac75368SArnd Bergmann unsigned char old_deny_bmap = stp->st_deny_bmap; 52781da177e4SLinus Torvalds 52796eb3a1d0SJeff Layton if (!test_access(open->op_share_access, stp)) 52803d694271SDai Ngo return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false); 52817e6a72e5SChristoph Hellwig 5282baeb4ff0SJeff Layton /* test and set deny mode */ 5283baeb4ff0SJeff Layton spin_lock(&fp->fi_lock); 5284baeb4ff0SJeff Layton status = nfs4_file_check_deny(fp, open->op_share_deny); 5285dcd779dcSJeff Layton switch (status) { 5286dcd779dcSJeff Layton case nfs_ok: 5287baeb4ff0SJeff Layton set_deny(open->op_share_deny, stp); 5288baeb4ff0SJeff Layton fp->fi_share_deny |= 5289baeb4ff0SJeff Layton (open->op_share_deny & NFS4_SHARE_DENY_BOTH); 5290dcd779dcSJeff Layton break; 5291dcd779dcSJeff Layton case nfserr_share_denied: 52923d694271SDai Ngo if (nfs4_resolve_deny_conflicts_locked(fp, false, 52933d694271SDai Ngo stp, open->op_share_deny, false)) 52943d694271SDai Ngo status = nfserr_jukebox; 5295dcd779dcSJeff Layton break; 52961da177e4SLinus Torvalds } 5297baeb4ff0SJeff Layton spin_unlock(&fp->fi_lock); 52981da177e4SLinus Torvalds 5299baeb4ff0SJeff Layton if (status != nfs_ok) 5300baeb4ff0SJeff Layton return status; 5301baeb4ff0SJeff Layton 5302baeb4ff0SJeff Layton status = nfsd4_truncate(rqstp, cur_fh, open); 5303baeb4ff0SJeff Layton if (status != nfs_ok) 5304baeb4ff0SJeff Layton reset_union_bmap_deny(old_deny_bmap, stp); 5305baeb4ff0SJeff Layton return status; 5306baeb4ff0SJeff Layton } 53071da177e4SLinus Torvalds 530814a24e99SJ. Bruce Fields /* Should we give out recallable state?: */ 530914a24e99SJ. Bruce Fields static bool nfsd4_cb_channel_good(struct nfs4_client *clp) 531014a24e99SJ. Bruce Fields { 531114a24e99SJ. Bruce Fields if (clp->cl_cb_state == NFSD4_CB_UP) 531214a24e99SJ. Bruce Fields return true; 531314a24e99SJ. Bruce Fields /* 531414a24e99SJ. Bruce Fields * In the sessions case, since we don't have to establish a 531514a24e99SJ. Bruce Fields * separate connection for callbacks, we assume it's OK 531614a24e99SJ. Bruce Fields * until we hear otherwise: 531714a24e99SJ. Bruce Fields */ 531814a24e99SJ. Bruce Fields return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN; 531914a24e99SJ. Bruce Fields } 532014a24e99SJ. Bruce Fields 5321653e514eSJ. Bruce Fields static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, 5322653e514eSJ. Bruce Fields int flag) 532322d38c4cSJ. Bruce Fields { 532422d38c4cSJ. Bruce Fields struct file_lock *fl; 532522d38c4cSJ. Bruce Fields 532622d38c4cSJ. Bruce Fields fl = locks_alloc_lock(); 532722d38c4cSJ. Bruce Fields if (!fl) 532822d38c4cSJ. Bruce Fields return NULL; 532922d38c4cSJ. Bruce Fields fl->fl_lmops = &nfsd_lease_mng_ops; 5330617588d5SJ. Bruce Fields fl->fl_flags = FL_DELEG; 533122d38c4cSJ. Bruce Fields fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK; 533222d38c4cSJ. Bruce Fields fl->fl_end = OFFSET_MAX; 5333653e514eSJ. Bruce Fields fl->fl_owner = (fl_owner_t)dp; 533422d38c4cSJ. Bruce Fields fl->fl_pid = current->tgid; 5335eb82dd39SJeff Layton fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file; 533622d38c4cSJ. Bruce Fields return fl; 533722d38c4cSJ. Bruce Fields } 533822d38c4cSJ. Bruce Fields 5339aba2072fSJ. Bruce Fields static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, 5340aba2072fSJ. Bruce Fields struct nfs4_file *fp) 5341aba2072fSJ. Bruce Fields { 5342aba2072fSJ. Bruce Fields struct nfs4_ol_stateid *st; 5343aba2072fSJ. Bruce Fields struct file *f = fp->fi_deleg_file->nf_file; 5344c65454a9SJeff Layton struct inode *ino = file_inode(f); 5345aba2072fSJ. Bruce Fields int writes; 5346aba2072fSJ. Bruce Fields 5347aba2072fSJ. Bruce Fields writes = atomic_read(&ino->i_writecount); 5348aba2072fSJ. Bruce Fields if (!writes) 5349aba2072fSJ. Bruce Fields return 0; 5350aba2072fSJ. Bruce Fields /* 5351aba2072fSJ. Bruce Fields * There could be multiple filehandles (hence multiple 5352aba2072fSJ. Bruce Fields * nfs4_files) referencing this file, but that's not too 5353aba2072fSJ. Bruce Fields * common; let's just give up in that case rather than 5354aba2072fSJ. Bruce Fields * trying to go look up all the clients using that other 5355aba2072fSJ. Bruce Fields * nfs4_file as well: 5356aba2072fSJ. Bruce Fields */ 5357aba2072fSJ. Bruce Fields if (fp->fi_aliased) 5358aba2072fSJ. Bruce Fields return -EAGAIN; 5359aba2072fSJ. Bruce Fields /* 5360aba2072fSJ. Bruce Fields * If there's a close in progress, make sure that we see it 5361aba2072fSJ. Bruce Fields * clear any fi_fds[] entries before we see it decrement 5362aba2072fSJ. Bruce Fields * i_writecount: 5363aba2072fSJ. Bruce Fields */ 5364aba2072fSJ. Bruce Fields smp_mb__after_atomic(); 5365aba2072fSJ. Bruce Fields 5366aba2072fSJ. Bruce Fields if (fp->fi_fds[O_WRONLY]) 5367aba2072fSJ. Bruce Fields writes--; 5368aba2072fSJ. Bruce Fields if (fp->fi_fds[O_RDWR]) 5369aba2072fSJ. Bruce Fields writes--; 5370aba2072fSJ. Bruce Fields if (writes > 0) 5371aba2072fSJ. Bruce Fields return -EAGAIN; /* There may be non-NFSv4 writers */ 5372aba2072fSJ. Bruce Fields /* 5373aba2072fSJ. Bruce Fields * It's possible there are non-NFSv4 write opens in progress, 5374aba2072fSJ. Bruce Fields * but if they haven't incremented i_writecount yet then they 5375aba2072fSJ. Bruce Fields * also haven't called break lease yet; so, they'll break this 5376aba2072fSJ. Bruce Fields * lease soon enough. So, all that's left to check for is NFSv4 5377aba2072fSJ. Bruce Fields * opens: 5378aba2072fSJ. Bruce Fields */ 5379aba2072fSJ. Bruce Fields spin_lock(&fp->fi_lock); 5380aba2072fSJ. Bruce Fields list_for_each_entry(st, &fp->fi_stateids, st_perfile) { 5381aba2072fSJ. Bruce Fields if (st->st_openstp == NULL /* it's an open */ && 5382aba2072fSJ. Bruce Fields access_permit_write(st) && 5383aba2072fSJ. Bruce Fields st->st_stid.sc_client != clp) { 5384aba2072fSJ. Bruce Fields spin_unlock(&fp->fi_lock); 5385aba2072fSJ. Bruce Fields return -EAGAIN; 5386aba2072fSJ. Bruce Fields } 5387aba2072fSJ. Bruce Fields } 5388aba2072fSJ. Bruce Fields spin_unlock(&fp->fi_lock); 5389aba2072fSJ. Bruce Fields /* 5390aba2072fSJ. Bruce Fields * There's a small chance that we could be racing with another 5391aba2072fSJ. Bruce Fields * NFSv4 open. However, any open that hasn't added itself to 5392aba2072fSJ. Bruce Fields * the fi_stateids list also hasn't called break_lease yet; so, 5393aba2072fSJ. Bruce Fields * they'll break this lease soon enough. 5394aba2072fSJ. Bruce Fields */ 5395aba2072fSJ. Bruce Fields return 0; 5396aba2072fSJ. Bruce Fields } 5397aba2072fSJ. Bruce Fields 5398876c553cSJeff Layton /* 5399876c553cSJeff Layton * It's possible that between opening the dentry and setting the delegation, 5400876c553cSJeff Layton * that it has been renamed or unlinked. Redo the lookup to verify that this 5401876c553cSJeff Layton * hasn't happened. 5402876c553cSJeff Layton */ 5403876c553cSJeff Layton static int 5404876c553cSJeff Layton nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp, 5405876c553cSJeff Layton struct svc_fh *parent) 5406876c553cSJeff Layton { 5407876c553cSJeff Layton struct svc_export *exp; 5408876c553cSJeff Layton struct dentry *child; 5409876c553cSJeff Layton __be32 err; 5410876c553cSJeff Layton 5411876c553cSJeff Layton err = nfsd_lookup_dentry(open->op_rqstp, parent, 5412876c553cSJeff Layton open->op_fname, open->op_fnamelen, 5413876c553cSJeff Layton &exp, &child); 5414876c553cSJeff Layton 5415876c553cSJeff Layton if (err) 5416876c553cSJeff Layton return -EAGAIN; 5417876c553cSJeff Layton 541850256e47SJeff Layton exp_put(exp); 5419876c553cSJeff Layton dput(child); 5420876c553cSJeff Layton if (child != file_dentry(fp->fi_deleg_file->nf_file)) 5421876c553cSJeff Layton return -EAGAIN; 5422876c553cSJeff Layton 5423876c553cSJeff Layton return 0; 5424876c553cSJeff Layton } 5425876c553cSJeff Layton 5426826b67e6SJeff Layton /* 5427826b67e6SJeff Layton * We avoid breaking delegations held by a client due to its own activity, but 5428826b67e6SJeff Layton * clearing setuid/setgid bits on a write is an implicit activity and the client 5429826b67e6SJeff Layton * may not notice and continue using the old mode. Avoid giving out a delegation 5430826b67e6SJeff Layton * on setuid/setgid files when the client is requesting an open for write. 5431826b67e6SJeff Layton */ 5432826b67e6SJeff Layton static int 5433826b67e6SJeff Layton nfsd4_verify_setuid_write(struct nfsd4_open *open, struct nfsd_file *nf) 5434826b67e6SJeff Layton { 5435826b67e6SJeff Layton struct inode *inode = file_inode(nf->nf_file); 5436826b67e6SJeff Layton 5437826b67e6SJeff Layton if ((open->op_share_access & NFS4_SHARE_ACCESS_WRITE) && 5438826b67e6SJeff Layton (inode->i_mode & (S_ISUID|S_ISGID))) 5439826b67e6SJeff Layton return -EAGAIN; 5440826b67e6SJeff Layton return 0; 5441826b67e6SJeff Layton } 5442826b67e6SJeff Layton 54430b26693cSJeff Layton static struct nfs4_delegation * 5444876c553cSJeff Layton nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, 5445876c553cSJeff Layton struct svc_fh *parent) 5446acfdf5c3SJ. Bruce Fields { 544768b18f52SJ. Bruce Fields int status = 0; 5448876c553cSJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 5449876c553cSJeff Layton struct nfs4_file *fp = stp->st_stid.sc_file; 5450876c553cSJeff Layton struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate; 54510b26693cSJeff Layton struct nfs4_delegation *dp; 5452eb82dd39SJeff Layton struct nfsd_file *nf; 5453353601e7SJ. Bruce Fields struct file_lock *fl; 5454417c6629SJeff Layton 5455353601e7SJ. Bruce Fields /* 5456353601e7SJ. Bruce Fields * The fi_had_conflict and nfs_get_existing_delegation checks 5457353601e7SJ. Bruce Fields * here are just optimizations; we'll need to recheck them at 5458353601e7SJ. Bruce Fields * the end: 5459353601e7SJ. Bruce Fields */ 5460bf7bd3e9SJ. Bruce Fields if (fp->fi_had_conflict) 54610b26693cSJeff Layton return ERR_PTR(-EAGAIN); 54620b26693cSJeff Layton 5463eb82dd39SJeff Layton nf = find_readable_file(fp); 5464eb82dd39SJeff Layton if (!nf) { 5465aba2072fSJ. Bruce Fields /* 5466aba2072fSJ. Bruce Fields * We probably could attempt another open and get a read 5467aba2072fSJ. Bruce Fields * delegation, but for now, don't bother until the 5468aba2072fSJ. Bruce Fields * client actually sends us one. 5469aba2072fSJ. Bruce Fields */ 5470aba2072fSJ. Bruce Fields return ERR_PTR(-EAGAIN); 5471353601e7SJ. Bruce Fields } 547234ed9872SAndrew Elble spin_lock(&state_lock); 547334ed9872SAndrew Elble spin_lock(&fp->fi_lock); 547468b18f52SJ. Bruce Fields if (nfs4_delegation_exists(clp, fp)) 547568b18f52SJ. Bruce Fields status = -EAGAIN; 5476826b67e6SJeff Layton else if (nfsd4_verify_setuid_write(open, nf)) 5477826b67e6SJeff Layton status = -EAGAIN; 5478353601e7SJ. Bruce Fields else if (!fp->fi_deleg_file) { 5479eb82dd39SJeff Layton fp->fi_deleg_file = nf; 5480353601e7SJ. Bruce Fields /* increment early to prevent fi_deleg_file from being 5481353601e7SJ. Bruce Fields * cleared */ 5482353601e7SJ. Bruce Fields fp->fi_delegees = 1; 5483eb82dd39SJeff Layton nf = NULL; 5484353601e7SJ. Bruce Fields } else 5485353601e7SJ. Bruce Fields fp->fi_delegees++; 5486353601e7SJ. Bruce Fields spin_unlock(&fp->fi_lock); 5487353601e7SJ. Bruce Fields spin_unlock(&state_lock); 5488eb82dd39SJeff Layton if (nf) 5489eb82dd39SJeff Layton nfsd_file_put(nf); 5490353601e7SJ. Bruce Fields if (status) 5491353601e7SJ. Bruce Fields return ERR_PTR(status); 5492353601e7SJ. Bruce Fields 5493353601e7SJ. Bruce Fields status = -ENOMEM; 5494bbf936edSJeff Layton dp = alloc_init_deleg(clp, fp, odstate); 5495353601e7SJ. Bruce Fields if (!dp) 5496353601e7SJ. Bruce Fields goto out_delegees; 5497353601e7SJ. Bruce Fields 5498353601e7SJ. Bruce Fields fl = nfs4_alloc_init_lease(dp, NFS4_OPEN_DELEGATE_READ); 5499353601e7SJ. Bruce Fields if (!fl) 5500bd8d7250SAndrew Elble goto out_clnt_odstate; 5501353601e7SJ. Bruce Fields 5502eb82dd39SJeff Layton status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL); 5503353601e7SJ. Bruce Fields if (fl) 5504353601e7SJ. Bruce Fields locks_free_lock(fl); 5505353601e7SJ. Bruce Fields if (status) 5506353601e7SJ. Bruce Fields goto out_clnt_odstate; 5507876c553cSJeff Layton 5508876c553cSJeff Layton if (parent) { 5509876c553cSJeff Layton status = nfsd4_verify_deleg_dentry(open, fp, parent); 5510876c553cSJeff Layton if (status) 5511876c553cSJeff Layton goto out_unlock; 5512876c553cSJeff Layton } 5513876c553cSJeff Layton 5514aba2072fSJ. Bruce Fields status = nfsd4_check_conflicting_opens(clp, fp); 5515aba2072fSJ. Bruce Fields if (status) 5516aba2072fSJ. Bruce Fields goto out_unlock; 5517353601e7SJ. Bruce Fields 5518826b67e6SJeff Layton /* 5519826b67e6SJeff Layton * Now that the deleg is set, check again to ensure that nothing 5520826b67e6SJeff Layton * raced in and changed the mode while we weren't lookng. 5521826b67e6SJeff Layton */ 5522826b67e6SJeff Layton status = nfsd4_verify_setuid_write(open, fp->fi_deleg_file); 5523826b67e6SJeff Layton if (status) 5524826b67e6SJeff Layton goto out_unlock; 5525826b67e6SJeff Layton 5526353601e7SJ. Bruce Fields spin_lock(&state_lock); 5527353601e7SJ. Bruce Fields spin_lock(&fp->fi_lock); 5528353601e7SJ. Bruce Fields if (fp->fi_had_conflict) 5529353601e7SJ. Bruce Fields status = -EAGAIN; 5530353601e7SJ. Bruce Fields else 5531353601e7SJ. Bruce Fields status = hash_delegation_locked(dp, fp); 553234ed9872SAndrew Elble spin_unlock(&fp->fi_lock); 553334ed9872SAndrew Elble spin_unlock(&state_lock); 553434ed9872SAndrew Elble 553534ed9872SAndrew Elble if (status) 5536692ad280SAndrew Elble goto out_unlock; 5537692ad280SAndrew Elble 55380b26693cSJeff Layton return dp; 5539692ad280SAndrew Elble out_unlock: 5540eb82dd39SJeff Layton vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp); 5541353601e7SJ. Bruce Fields out_clnt_odstate: 5542353601e7SJ. Bruce Fields put_clnt_odstate(dp->dl_clnt_odstate); 5543353601e7SJ. Bruce Fields nfs4_put_stid(&dp->dl_stid); 5544353601e7SJ. Bruce Fields out_delegees: 5545353601e7SJ. Bruce Fields put_deleg_file(fp); 5546353601e7SJ. Bruce Fields return ERR_PTR(status); 5547edab9782SJ. Bruce Fields } 5548edab9782SJ. Bruce Fields 55494aa8913cSBenny Halevy static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) 55504aa8913cSBenny Halevy { 55514aa8913cSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 55524aa8913cSBenny Halevy if (status == -EAGAIN) 55534aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CONTENTION; 55544aa8913cSBenny Halevy else { 55554aa8913cSBenny Halevy open->op_why_no_deleg = WND4_RESOURCE; 55564aa8913cSBenny Halevy switch (open->op_deleg_want) { 55574aa8913cSBenny Halevy case NFS4_SHARE_WANT_READ_DELEG: 55584aa8913cSBenny Halevy case NFS4_SHARE_WANT_WRITE_DELEG: 55594aa8913cSBenny Halevy case NFS4_SHARE_WANT_ANY_DELEG: 55604aa8913cSBenny Halevy break; 55614aa8913cSBenny Halevy case NFS4_SHARE_WANT_CANCEL: 55624aa8913cSBenny Halevy open->op_why_no_deleg = WND4_CANCELLED; 55634aa8913cSBenny Halevy break; 55644aa8913cSBenny Halevy case NFS4_SHARE_WANT_NO_DELEG: 5565063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 55664aa8913cSBenny Halevy } 55674aa8913cSBenny Halevy } 55684aa8913cSBenny Halevy } 55694aa8913cSBenny Halevy 55701da177e4SLinus Torvalds /* 55711da177e4SLinus Torvalds * Attempt to hand out a delegation. 557299c41515SJ. Bruce Fields * 557399c41515SJ. Bruce Fields * Note we don't support write delegations, and won't until the vfs has 557499c41515SJ. Bruce Fields * proper support for them. 55751da177e4SLinus Torvalds */ 55761da177e4SLinus Torvalds static void 5577876c553cSJeff Layton nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, 5578876c553cSJeff Layton struct svc_fh *currentfh) 55791da177e4SLinus Torvalds { 55801da177e4SLinus Torvalds struct nfs4_delegation *dp; 55814cf59221SJeff Layton struct nfs4_openowner *oo = openowner(stp->st_stateowner); 55824cf59221SJeff Layton struct nfs4_client *clp = stp->st_stid.sc_client; 5583876c553cSJeff Layton struct svc_fh *parent = NULL; 558414a24e99SJ. Bruce Fields int cb_up; 558599c41515SJ. Bruce Fields int status = 0; 55861da177e4SLinus Torvalds 5587fe0750e5SJ. Bruce Fields cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); 55887b190fecSNeilBrown open->op_recall = 0; 55897b190fecSNeilBrown switch (open->op_claim_type) { 55907b190fecSNeilBrown case NFS4_OPEN_CLAIM_PREVIOUS: 55912bf23875SJ. Bruce Fields if (!cb_up) 55927b190fecSNeilBrown open->op_recall = 1; 559399c41515SJ. Bruce Fields if (open->op_delegate_type != NFS4_OPEN_DELEGATE_READ) 559499c41515SJ. Bruce Fields goto out_no_deleg; 55957b190fecSNeilBrown break; 55967b190fecSNeilBrown case NFS4_OPEN_CLAIM_NULL: 5597876c553cSJeff Layton parent = currentfh; 5598876c553cSJeff Layton fallthrough; 5599ed47b062SMing Chen case NFS4_OPEN_CLAIM_FH: 560099c41515SJ. Bruce Fields /* 560199c41515SJ. Bruce Fields * Let's not give out any delegations till everyone's 5602c87fb4a3SJ. Bruce Fields * had the chance to reclaim theirs, *and* until 5603c87fb4a3SJ. Bruce Fields * NLM locks have all been reclaimed: 560499c41515SJ. Bruce Fields */ 56054cf59221SJeff Layton if (locks_in_grace(clp->net)) 560699c41515SJ. Bruce Fields goto out_no_deleg; 5607dad1c067SJ. Bruce Fields if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) 560899c41515SJ. Bruce Fields goto out_no_deleg; 56097b190fecSNeilBrown break; 56107b190fecSNeilBrown default: 561199c41515SJ. Bruce Fields goto out_no_deleg; 56127b190fecSNeilBrown } 5613876c553cSJeff Layton dp = nfs4_set_delegation(open, stp, parent); 56140b26693cSJeff Layton if (IS_ERR(dp)) 5615dd239cc0SJ. Bruce Fields goto out_no_deleg; 56161da177e4SLinus Torvalds 5617d5477a8dSJ. Bruce Fields memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); 56181da177e4SLinus Torvalds 56193caf9175SHou Tao trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); 562099c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; 562167cb1279STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5622dd239cc0SJ. Bruce Fields return; 5623dd239cc0SJ. Bruce Fields out_no_deleg: 562499c41515SJ. Bruce Fields open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; 56257b190fecSNeilBrown if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && 5626d08d32e6SJ. Bruce Fields open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) { 56271da177e4SLinus Torvalds dprintk("NFSD: WARNING: refusing delegation reclaim\n"); 5628d08d32e6SJ. Bruce Fields open->op_recall = 1; 5629d08d32e6SJ. Bruce Fields } 5630dd239cc0SJ. Bruce Fields 5631dd239cc0SJ. Bruce Fields /* 4.1 client asking for a delegation? */ 5632dd239cc0SJ. Bruce Fields if (open->op_deleg_want) 5633dd239cc0SJ. Bruce Fields nfsd4_open_deleg_none_ext(open, status); 5634dd239cc0SJ. Bruce Fields return; 56351da177e4SLinus Torvalds } 56361da177e4SLinus Torvalds 5637e27f49c3SBenny Halevy static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, 5638e27f49c3SBenny Halevy struct nfs4_delegation *dp) 5639e27f49c3SBenny Halevy { 5640e27f49c3SBenny Halevy if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && 5641e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5642e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5643e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; 5644e27f49c3SBenny Halevy } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && 5645e27f49c3SBenny Halevy dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { 5646e27f49c3SBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5647e27f49c3SBenny Halevy open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; 5648e27f49c3SBenny Halevy } 5649e27f49c3SBenny Halevy /* Otherwise the client must be confused wanting a delegation 5650e27f49c3SBenny Halevy * it already has, therefore we don't return 5651e27f49c3SBenny Halevy * NFS4_OPEN_DELEGATE_NONE_EXT and reason. 5652e27f49c3SBenny Halevy */ 5653e27f49c3SBenny Halevy } 5654e27f49c3SBenny Halevy 56557e2ce0ccSChuck Lever /** 56567e2ce0ccSChuck Lever * nfsd4_process_open2 - finish open processing 56577e2ce0ccSChuck Lever * @rqstp: the RPC transaction being executed 56587e2ce0ccSChuck Lever * @current_fh: NFSv4 COMPOUND's current filehandle 56597e2ce0ccSChuck Lever * @open: OPEN arguments 56607e2ce0ccSChuck Lever * 56617e2ce0ccSChuck Lever * If successful, (1) truncate the file if open->op_truncate was 56627e2ce0ccSChuck Lever * set, (2) set open->op_stateid, (3) set open->op_delegation. 56637e2ce0ccSChuck Lever * 56647e2ce0ccSChuck Lever * Returns %nfs_ok on success; otherwise an nfs4stat value in 56657e2ce0ccSChuck Lever * network byte order is returned. 56667e2ce0ccSChuck Lever */ 5667b37ad28bSAl Viro __be32 56681da177e4SLinus Torvalds nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) 56691da177e4SLinus Torvalds { 56706668958fSAndy Adamson struct nfsd4_compoundres *resp = rqstp->rq_resp; 567138c2f4b1SJ. Bruce Fields struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; 56721da177e4SLinus Torvalds struct nfs4_file *fp = NULL; 5673dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp = NULL; 5674567d9829SNeilBrown struct nfs4_delegation *dp = NULL; 5675b37ad28bSAl Viro __be32 status; 5676d8a1a000STrond Myklebust bool new_stp = false; 56771da177e4SLinus Torvalds 56781da177e4SLinus Torvalds /* 56791da177e4SLinus Torvalds * Lookup file; if found, lookup stateid and check open request, 56801da177e4SLinus Torvalds * and check for delegations in the process of being recalled. 56811da177e4SLinus Torvalds * If not found, create the nfs4_file struct 56821da177e4SLinus Torvalds */ 56839270fc51SChuck Lever fp = nfsd4_file_hash_insert(open->op_file, current_fh); 5684d47b295eSChuck Lever if (unlikely(!fp)) 5685d47b295eSChuck Lever return nfserr_jukebox; 5686950e0118STrond Myklebust if (fp != open->op_file) { 568741d22663SJ. Bruce Fields status = nfs4_check_deleg(cl, open, &dp); 5688c44c5eebSNeilBrown if (status) 5689c44c5eebSNeilBrown goto out; 569015ca08d3STrond Myklebust stp = nfsd4_find_and_lock_existing_open(fp, open); 56911da177e4SLinus Torvalds } else { 5692950e0118STrond Myklebust open->op_file = NULL; 5693c44c5eebSNeilBrown status = nfserr_bad_stateid; 56948b289b2cSJ. Bruce Fields if (nfsd4_is_deleg_cur(open)) 5695c44c5eebSNeilBrown goto out; 56961da177e4SLinus Torvalds } 56971da177e4SLinus Torvalds 5698d8a1a000STrond Myklebust if (!stp) { 5699d8a1a000STrond Myklebust stp = init_open_stateid(fp, open); 5700d8a1a000STrond Myklebust if (!open->op_stp) 5701d8a1a000STrond Myklebust new_stp = true; 5702d8a1a000STrond Myklebust } 5703d8a1a000STrond Myklebust 57041da177e4SLinus Torvalds /* 57051da177e4SLinus Torvalds * OPEN the file, or upgrade an existing OPEN. 57061da177e4SLinus Torvalds * If truncate fails, the OPEN fails. 5707d8a1a000STrond Myklebust * 5708d8a1a000STrond Myklebust * stp is already locked. 57091da177e4SLinus Torvalds */ 5710d8a1a000STrond Myklebust if (!new_stp) { 57111da177e4SLinus Torvalds /* Stateid was found, this is an OPEN upgrade */ 5712f9d7562fSJ. Bruce Fields status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 571335a92fe8SJeff Layton if (status) { 5714feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 57151da177e4SLinus Torvalds goto out; 571635a92fe8SJeff Layton } 57171da177e4SLinus Torvalds } else { 57183d694271SDai Ngo status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true); 57196eb3a1d0SJeff Layton if (status) { 5720d8a1a000STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 57216eb3a1d0SJeff Layton release_open_stateid(stp); 5722d8a1a000STrond Myklebust mutex_unlock(&stp->st_mutex); 57236eb3a1d0SJeff Layton goto out; 57246eb3a1d0SJeff Layton } 57258287f009SSachin Bhamare 57268287f009SSachin Bhamare stp->st_clnt_odstate = find_or_hash_clnt_odstate(fp, 57278287f009SSachin Bhamare open->op_odstate); 57288287f009SSachin Bhamare if (stp->st_clnt_odstate == open->op_odstate) 57298287f009SSachin Bhamare open->op_odstate = NULL; 57301da177e4SLinus Torvalds } 5731d8a1a000STrond Myklebust 57329767feb2SJeff Layton nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 5733feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 57341da177e4SLinus Torvalds 5735d24433cdSBenny Halevy if (nfsd4_has_session(&resp->cstate)) { 5736d24433cdSBenny Halevy if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 5737d24433cdSBenny Halevy open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; 5738d24433cdSBenny Halevy open->op_why_no_deleg = WND4_NOT_WANTED; 5739d24433cdSBenny Halevy goto nodeleg; 5740d24433cdSBenny Halevy } 5741d24433cdSBenny Halevy } 5742d24433cdSBenny Halevy 57431da177e4SLinus Torvalds /* 57441da177e4SLinus Torvalds * Attempt to hand out a delegation. No error return, because the 57451da177e4SLinus Torvalds * OPEN succeeds even if we fail. 57461da177e4SLinus Torvalds */ 5747876c553cSJeff Layton nfs4_open_delegation(open, stp, &resp->cstate.current_fh); 5748d24433cdSBenny Halevy nodeleg: 57491da177e4SLinus Torvalds status = nfs_ok; 57503caf9175SHou Tao trace_nfsd_open(&stp->st_stid.sc_stateid); 57511da177e4SLinus Torvalds out: 5752d24433cdSBenny Halevy /* 4.1 client trying to upgrade/downgrade delegation? */ 5753d24433cdSBenny Halevy if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && 5754e27f49c3SBenny Halevy open->op_deleg_want) 5755e27f49c3SBenny Halevy nfsd4_deleg_xgrade_none_ext(open, dp); 5756d24433cdSBenny Halevy 575713cd2184SNeilBrown if (fp) 575813cd2184SNeilBrown put_nfs4_file(fp); 575937515177SNeilBrown if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) 576087186022SKinglong Mee open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; 57611da177e4SLinus Torvalds /* 57621da177e4SLinus Torvalds * To finish the open response, we just need to set the rflags. 57631da177e4SLinus Torvalds */ 57641da177e4SLinus Torvalds open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; 576519e4c347SJeff Layton if (nfsd4_has_session(&resp->cstate)) 576619e4c347SJeff Layton open->op_rflags |= NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK; 576719e4c347SJeff Layton else if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED)) 57681da177e4SLinus Torvalds open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; 576919e4c347SJeff Layton 5770dcd94cc2STrond Myklebust if (dp) 5771dcd94cc2STrond Myklebust nfs4_put_stid(&dp->dl_stid); 5772d6f2bc5dSTrond Myklebust if (stp) 5773d6f2bc5dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 57741da177e4SLinus Torvalds 57751da177e4SLinus Torvalds return status; 57761da177e4SLinus Torvalds } 57771da177e4SLinus Torvalds 577858fb12e6SJeff Layton void nfsd4_cleanup_open_state(struct nfsd4_compound_state *cstate, 577942297899SJeff Layton struct nfsd4_open *open) 5780d29b20cdSJ. Bruce Fields { 5781d29b20cdSJ. Bruce Fields if (open->op_openowner) { 5782d3134b10SJeff Layton struct nfs4_stateowner *so = &open->op_openowner->oo_owner; 5783d29b20cdSJ. Bruce Fields 5784d3134b10SJeff Layton nfsd4_cstate_assign_replay(cstate, so); 5785d3134b10SJeff Layton nfs4_put_stateowner(so); 5786d29b20cdSJ. Bruce Fields } 578732513b40SJ. Bruce Fields if (open->op_file) 57885b095e99SJeff Layton kmem_cache_free(file_slab, open->op_file); 57894cdc951bSJ. Bruce Fields if (open->op_stp) 57906011695dSTrond Myklebust nfs4_put_stid(&open->op_stp->st_stid); 57918287f009SSachin Bhamare if (open->op_odstate) 57928287f009SSachin Bhamare kmem_cache_free(odstate_slab, open->op_odstate); 5793d29b20cdSJ. Bruce Fields } 5794d29b20cdSJ. Bruce Fields 5795b37ad28bSAl Viro __be32 5796b591480bSJ.Bruce Fields nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 5797eb69853dSChristoph Hellwig union nfsd4_op_u *u) 57981da177e4SLinus Torvalds { 5799eb69853dSChristoph Hellwig clientid_t *clid = &u->renew; 58001da177e4SLinus Torvalds struct nfs4_client *clp; 5801b37ad28bSAl Viro __be32 status; 58027f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 58031da177e4SLinus Torvalds 5804dd5e3fbcSChuck Lever trace_nfsd_clid_renew(clid); 5805f71475baSJ. Bruce Fields status = set_client(clid, cstate, nn); 58069b2ef62bSJ. Bruce Fields if (status) 5807b4587eb2SJ. Bruce Fields return status; 58084b24ca7dSJeff Layton clp = cstate->clp; 5809ea1da636SNeilBrown if (!list_empty(&clp->cl_delegations) 581077a3569dSJ. Bruce Fields && clp->cl_cb_state != NFSD4_CB_UP) 5811b4587eb2SJ. Bruce Fields return nfserr_cb_path_down; 5812b4587eb2SJ. Bruce Fields return nfs_ok; 58131da177e4SLinus Torvalds } 58141da177e4SLinus Torvalds 58157f5ef2e9SJeff Layton void 581612760c66SStanislav Kinsbursky nfsd4_end_grace(struct nfsd_net *nn) 5817a76b4319SNeilBrown { 581833dcc481SJeff Layton /* do nothing if grace period already ended */ 5819a51c84edSStanislav Kinsbursky if (nn->grace_ended) 582033dcc481SJeff Layton return; 582133dcc481SJeff Layton 5822dd5e3fbcSChuck Lever trace_nfsd_grace_complete(nn); 5823a51c84edSStanislav Kinsbursky nn->grace_ended = true; 582470b28235SJ. Bruce Fields /* 582570b28235SJ. Bruce Fields * If the server goes down again right now, an NFSv4 582670b28235SJ. Bruce Fields * client will still be allowed to reclaim after it comes back up, 582770b28235SJ. Bruce Fields * even if it hasn't yet had a chance to reclaim state this time. 582870b28235SJ. Bruce Fields * 582970b28235SJ. Bruce Fields */ 5830919b8049SJeff Layton nfsd4_record_grace_done(nn); 583170b28235SJ. Bruce Fields /* 583270b28235SJ. Bruce Fields * At this point, NFSv4 clients can still reclaim. But if the 583370b28235SJ. Bruce Fields * server crashes, any that have not yet reclaimed will be out 583470b28235SJ. Bruce Fields * of luck on the next boot. 583570b28235SJ. Bruce Fields * 583670b28235SJ. Bruce Fields * (NFSv4.1+ clients are considered to have reclaimed once they 583770b28235SJ. Bruce Fields * call RECLAIM_COMPLETE. NFSv4.0 clients are considered to 583870b28235SJ. Bruce Fields * have reclaimed after their first OPEN.) 583970b28235SJ. Bruce Fields */ 58405e1533c7SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 584170b28235SJ. Bruce Fields /* 584270b28235SJ. Bruce Fields * At this point, and once lockd and/or any other containers 584370b28235SJ. Bruce Fields * exit their grace period, further reclaims will fail and 584470b28235SJ. Bruce Fields * regular locking can resume. 584570b28235SJ. Bruce Fields */ 5846a76b4319SNeilBrown } 5847a76b4319SNeilBrown 584803f318caSJ. Bruce Fields /* 584903f318caSJ. Bruce Fields * If we've waited a lease period but there are still clients trying to 585003f318caSJ. Bruce Fields * reclaim, wait a little longer to give them a chance to finish. 585103f318caSJ. Bruce Fields */ 585203f318caSJ. Bruce Fields static bool clients_still_reclaiming(struct nfsd_net *nn) 585303f318caSJ. Bruce Fields { 585420b7d86fSArnd Bergmann time64_t double_grace_period_end = nn->boot_time + 585520b7d86fSArnd Bergmann 2 * nn->nfsd4_lease; 585603f318caSJ. Bruce Fields 5857362063a5SScott Mayhew if (nn->track_reclaim_completes && 5858362063a5SScott Mayhew atomic_read(&nn->nr_reclaim_complete) == 5859362063a5SScott Mayhew nn->reclaim_str_hashtbl_size) 5860362063a5SScott Mayhew return false; 586103f318caSJ. Bruce Fields if (!nn->somebody_reclaimed) 586203f318caSJ. Bruce Fields return false; 586303f318caSJ. Bruce Fields nn->somebody_reclaimed = false; 586403f318caSJ. Bruce Fields /* 586503f318caSJ. Bruce Fields * If we've given them *two* lease times to reclaim, and they're 586603f318caSJ. Bruce Fields * still not done, give up: 586703f318caSJ. Bruce Fields */ 586820b7d86fSArnd Bergmann if (ktime_get_boottime_seconds() > double_grace_period_end) 586903f318caSJ. Bruce Fields return false; 587003f318caSJ. Bruce Fields return true; 587103f318caSJ. Bruce Fields } 587203f318caSJ. Bruce Fields 58737f7e7a40SJ. Bruce Fields struct laundry_time { 58747f7e7a40SJ. Bruce Fields time64_t cutoff; 58757f7e7a40SJ. Bruce Fields time64_t new_timeo; 58767f7e7a40SJ. Bruce Fields }; 58777f7e7a40SJ. Bruce Fields 58787f7e7a40SJ. Bruce Fields static bool state_expired(struct laundry_time *lt, time64_t last_refresh) 58797f7e7a40SJ. Bruce Fields { 58807f7e7a40SJ. Bruce Fields time64_t time_remaining; 58817f7e7a40SJ. Bruce Fields 58827f7e7a40SJ. Bruce Fields if (last_refresh < lt->cutoff) 58837f7e7a40SJ. Bruce Fields return true; 58847f7e7a40SJ. Bruce Fields time_remaining = last_refresh - lt->cutoff; 58857f7e7a40SJ. Bruce Fields lt->new_timeo = min(lt->new_timeo, time_remaining); 58867f7e7a40SJ. Bruce Fields return false; 58877f7e7a40SJ. Bruce Fields } 58887f7e7a40SJ. Bruce Fields 5889f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 5890f4e44b39SDai Ngo void nfsd4_ssc_init_umount_work(struct nfsd_net *nn) 5891f4e44b39SDai Ngo { 5892f4e44b39SDai Ngo spin_lock_init(&nn->nfsd_ssc_lock); 5893f4e44b39SDai Ngo INIT_LIST_HEAD(&nn->nfsd_ssc_mount_list); 5894f4e44b39SDai Ngo init_waitqueue_head(&nn->nfsd_ssc_waitq); 5895f4e44b39SDai Ngo } 5896f4e44b39SDai Ngo EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); 5897f4e44b39SDai Ngo 5898f4e44b39SDai Ngo /* 5899f4e44b39SDai Ngo * This is called when nfsd is being shutdown, after all inter_ssc 5900f4e44b39SDai Ngo * cleanup were done, to destroy the ssc delayed unmount list. 5901f4e44b39SDai Ngo */ 5902f4e44b39SDai Ngo static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) 5903f4e44b39SDai Ngo { 5904f47dc2d3SDai Ngo struct nfsd4_ssc_umount_item *ni = NULL; 5905f4e44b39SDai Ngo struct nfsd4_ssc_umount_item *tmp; 5906f4e44b39SDai Ngo 5907f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5908f4e44b39SDai Ngo list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { 5909f4e44b39SDai Ngo list_del(&ni->nsui_list); 5910f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5911f4e44b39SDai Ngo mntput(ni->nsui_vfsmount); 5912f4e44b39SDai Ngo kfree(ni); 5913f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5914f4e44b39SDai Ngo } 5915f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5916f4e44b39SDai Ngo } 5917f4e44b39SDai Ngo 5918f4e44b39SDai Ngo static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) 5919f4e44b39SDai Ngo { 5920f4e44b39SDai Ngo bool do_wakeup = false; 59218e70bf27SColin Ian King struct nfsd4_ssc_umount_item *ni = NULL; 5922f4e44b39SDai Ngo struct nfsd4_ssc_umount_item *tmp; 5923f4e44b39SDai Ngo 5924f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5925f4e44b39SDai Ngo list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { 5926f4e44b39SDai Ngo if (time_after(jiffies, ni->nsui_expire)) { 5927f4e44b39SDai Ngo if (refcount_read(&ni->nsui_refcnt) > 1) 5928f4e44b39SDai Ngo continue; 5929f4e44b39SDai Ngo 5930f4e44b39SDai Ngo /* mark being unmount */ 5931f4e44b39SDai Ngo ni->nsui_busy = true; 5932f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5933f4e44b39SDai Ngo mntput(ni->nsui_vfsmount); 5934f4e44b39SDai Ngo spin_lock(&nn->nfsd_ssc_lock); 5935f4e44b39SDai Ngo 5936f4e44b39SDai Ngo /* waiters need to start from begin of list */ 5937f4e44b39SDai Ngo list_del(&ni->nsui_list); 5938f4e44b39SDai Ngo kfree(ni); 5939f4e44b39SDai Ngo 5940f4e44b39SDai Ngo /* wakeup ssc_connect waiters */ 5941f4e44b39SDai Ngo do_wakeup = true; 5942f4e44b39SDai Ngo continue; 5943f4e44b39SDai Ngo } 5944f4e44b39SDai Ngo break; 5945f4e44b39SDai Ngo } 5946f4e44b39SDai Ngo if (do_wakeup) 5947f4e44b39SDai Ngo wake_up_all(&nn->nfsd_ssc_waitq); 5948f4e44b39SDai Ngo spin_unlock(&nn->nfsd_ssc_lock); 5949f4e44b39SDai Ngo } 5950f4e44b39SDai Ngo #endif 5951f4e44b39SDai Ngo 595227431affSDai Ngo /* Check if any lock belonging to this lockowner has any blockers */ 59533d694271SDai Ngo static bool 595427431affSDai Ngo nfs4_lockowner_has_blockers(struct nfs4_lockowner *lo) 595527431affSDai Ngo { 595627431affSDai Ngo struct file_lock_context *ctx; 595727431affSDai Ngo struct nfs4_ol_stateid *stp; 595827431affSDai Ngo struct nfs4_file *nf; 595927431affSDai Ngo 596027431affSDai Ngo list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) { 596127431affSDai Ngo nf = stp->st_stid.sc_file; 596277c67530SJeff Layton ctx = locks_inode_context(nf->fi_inode); 596327431affSDai Ngo if (!ctx) 596427431affSDai Ngo continue; 596527431affSDai Ngo if (locks_owner_has_blockers(ctx, lo)) 596627431affSDai Ngo return true; 596727431affSDai Ngo } 596827431affSDai Ngo return false; 596927431affSDai Ngo } 597027431affSDai Ngo 597127431affSDai Ngo static bool 597227431affSDai Ngo nfs4_anylock_blockers(struct nfs4_client *clp) 59733d694271SDai Ngo { 59743d694271SDai Ngo int i; 59753d694271SDai Ngo struct nfs4_stateowner *so; 597627431affSDai Ngo struct nfs4_lockowner *lo; 59773d694271SDai Ngo 597827431affSDai Ngo if (atomic_read(&clp->cl_delegs_in_recall)) 597927431affSDai Ngo return true; 59803d694271SDai Ngo spin_lock(&clp->cl_lock); 59813d694271SDai Ngo for (i = 0; i < OWNER_HASH_SIZE; i++) { 59823d694271SDai Ngo list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i], 59833d694271SDai Ngo so_strhash) { 59843d694271SDai Ngo if (so->so_is_open_owner) 59853d694271SDai Ngo continue; 598627431affSDai Ngo lo = lockowner(so); 598727431affSDai Ngo if (nfs4_lockowner_has_blockers(lo)) { 59883d694271SDai Ngo spin_unlock(&clp->cl_lock); 59893d694271SDai Ngo return true; 59903d694271SDai Ngo } 59913d694271SDai Ngo } 59923d694271SDai Ngo } 599327431affSDai Ngo spin_unlock(&clp->cl_lock); 599466af2579SDai Ngo return false; 599566af2579SDai Ngo } 599666af2579SDai Ngo 599766af2579SDai Ngo static void 599866af2579SDai Ngo nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, 599966af2579SDai Ngo struct laundry_time *lt) 600066af2579SDai Ngo { 60014271c2c0SDai Ngo unsigned int maxreap, reapcnt = 0; 600266af2579SDai Ngo struct list_head *pos, *next; 600366af2579SDai Ngo struct nfs4_client *clp; 600466af2579SDai Ngo 60054271c2c0SDai Ngo maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ? 60064271c2c0SDai Ngo NFSD_CLIENT_MAX_TRIM_PER_RUN : 0; 600766af2579SDai Ngo INIT_LIST_HEAD(reaplist); 600866af2579SDai Ngo spin_lock(&nn->client_lock); 600966af2579SDai Ngo list_for_each_safe(pos, next, &nn->client_lru) { 601066af2579SDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 601166af2579SDai Ngo if (clp->cl_state == NFSD4_EXPIRABLE) 601266af2579SDai Ngo goto exp_client; 601366af2579SDai Ngo if (!state_expired(lt, clp->cl_time)) 601466af2579SDai Ngo break; 60153a4ea23dSDai Ngo if (!atomic_read(&clp->cl_rpc_users)) { 60163a4ea23dSDai Ngo if (clp->cl_state == NFSD4_ACTIVE) 60173a4ea23dSDai Ngo atomic_inc(&nn->nfsd_courtesy_clients); 601866af2579SDai Ngo clp->cl_state = NFSD4_COURTESY; 60193a4ea23dSDai Ngo } 60204271c2c0SDai Ngo if (!client_has_state(clp)) 602166af2579SDai Ngo goto exp_client; 60224271c2c0SDai Ngo if (!nfs4_anylock_blockers(clp)) 60234271c2c0SDai Ngo if (reapcnt >= maxreap) 60244271c2c0SDai Ngo continue; 602566af2579SDai Ngo exp_client: 60264271c2c0SDai Ngo if (!mark_client_expired_locked(clp)) { 602766af2579SDai Ngo list_add(&clp->cl_lru, reaplist); 60284271c2c0SDai Ngo reapcnt++; 602966af2579SDai Ngo } 603066af2579SDai Ngo } 603166af2579SDai Ngo spin_unlock(&nn->client_lock); 603266af2579SDai Ngo } 603366af2579SDai Ngo 60347746b32fSDai Ngo static void 60357746b32fSDai Ngo nfs4_get_courtesy_client_reaplist(struct nfsd_net *nn, 60367746b32fSDai Ngo struct list_head *reaplist) 60377746b32fSDai Ngo { 60387746b32fSDai Ngo unsigned int maxreap = 0, reapcnt = 0; 60397746b32fSDai Ngo struct list_head *pos, *next; 60407746b32fSDai Ngo struct nfs4_client *clp; 60417746b32fSDai Ngo 60427746b32fSDai Ngo maxreap = NFSD_CLIENT_MAX_TRIM_PER_RUN; 60437746b32fSDai Ngo INIT_LIST_HEAD(reaplist); 60447746b32fSDai Ngo 60457746b32fSDai Ngo spin_lock(&nn->client_lock); 60467746b32fSDai Ngo list_for_each_safe(pos, next, &nn->client_lru) { 60477746b32fSDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 60487746b32fSDai Ngo if (clp->cl_state == NFSD4_ACTIVE) 60497746b32fSDai Ngo break; 60507746b32fSDai Ngo if (reapcnt >= maxreap) 60517746b32fSDai Ngo break; 60527746b32fSDai Ngo if (!mark_client_expired_locked(clp)) { 60537746b32fSDai Ngo list_add(&clp->cl_lru, reaplist); 60547746b32fSDai Ngo reapcnt++; 60557746b32fSDai Ngo } 60567746b32fSDai Ngo } 60577746b32fSDai Ngo spin_unlock(&nn->client_lock); 60587746b32fSDai Ngo } 60597746b32fSDai Ngo 60607746b32fSDai Ngo static void 60617746b32fSDai Ngo nfs4_process_client_reaplist(struct list_head *reaplist) 60627746b32fSDai Ngo { 60637746b32fSDai Ngo struct list_head *pos, *next; 60647746b32fSDai Ngo struct nfs4_client *clp; 60657746b32fSDai Ngo 60667746b32fSDai Ngo list_for_each_safe(pos, next, reaplist) { 60677746b32fSDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 60687746b32fSDai Ngo trace_nfsd_clid_purged(&clp->cl_clientid); 60697746b32fSDai Ngo list_del_init(&clp->cl_lru); 60707746b32fSDai Ngo expire_client(clp); 60717746b32fSDai Ngo } 60727746b32fSDai Ngo } 60737746b32fSDai Ngo 607420b7d86fSArnd Bergmann static time64_t 607509121281SStanislav Kinsbursky nfs4_laundromat(struct nfsd_net *nn) 60761da177e4SLinus Torvalds { 6077fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 60781da177e4SLinus Torvalds struct nfs4_delegation *dp; 6079217526e7SJeff Layton struct nfs4_ol_stateid *stp; 60807919d0a2SJeff Layton struct nfsd4_blocked_lock *nbl; 60811da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 60827f7e7a40SJ. Bruce Fields struct laundry_time lt = { 60837f7e7a40SJ. Bruce Fields .cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease, 60847f7e7a40SJ. Bruce Fields .new_timeo = nn->nfsd4_lease 60857f7e7a40SJ. Bruce Fields }; 6086624322f1SOlga Kornievskaia struct nfs4_cpntf_state *cps; 6087624322f1SOlga Kornievskaia copy_stateid_t *cps_t; 6088624322f1SOlga Kornievskaia int i; 60891da177e4SLinus Torvalds 609003f318caSJ. Bruce Fields if (clients_still_reclaiming(nn)) { 60917f7e7a40SJ. Bruce Fields lt.new_timeo = 0; 609203f318caSJ. Bruce Fields goto out; 609303f318caSJ. Bruce Fields } 609412760c66SStanislav Kinsbursky nfsd4_end_grace(nn); 6095624322f1SOlga Kornievskaia 6096624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6097624322f1SOlga Kornievskaia idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { 6098624322f1SOlga Kornievskaia cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); 6099781fde1aSChuck Lever if (cps->cp_stateid.cs_type == NFS4_COPYNOTIFY_STID && 61007f7e7a40SJ. Bruce Fields state_expired(<, cps->cpntf_time)) 6101624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 6102624322f1SOlga Kornievskaia } 6103624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 610466af2579SDai Ngo nfs4_get_client_reaplist(nn, &reaplist, <); 61057746b32fSDai Ngo nfs4_process_client_reaplist(&reaplist); 61067746b32fSDai Ngo 6107cdc97505SBenny Halevy spin_lock(&state_lock); 6108e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 61091da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 61107f7e7a40SJ. Bruce Fields if (!state_expired(<, dp->dl_time)) 61111da177e4SLinus Torvalds break; 61123fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 611342690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 61141da177e4SLinus Torvalds } 6115cdc97505SBenny Halevy spin_unlock(&state_lock); 61162d4a532dSJeff Layton while (!list_empty(&reaplist)) { 61172d4a532dSJeff Layton dp = list_first_entry(&reaplist, struct nfs4_delegation, 61182d4a532dSJeff Layton dl_recall_lru); 61192d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 61203bd64a5bSJ. Bruce Fields revoke_delegation(dp); 61211da177e4SLinus Torvalds } 6122217526e7SJeff Layton 6123217526e7SJeff Layton spin_lock(&nn->client_lock); 6124217526e7SJeff Layton while (!list_empty(&nn->close_lru)) { 6125217526e7SJeff Layton oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, 6126217526e7SJeff Layton oo_close_lru); 61277f7e7a40SJ. Bruce Fields if (!state_expired(<, oo->oo_time)) 61281da177e4SLinus Torvalds break; 6129217526e7SJeff Layton list_del_init(&oo->oo_close_lru); 6130217526e7SJeff Layton stp = oo->oo_last_closed_stid; 6131217526e7SJeff Layton oo->oo_last_closed_stid = NULL; 6132217526e7SJeff Layton spin_unlock(&nn->client_lock); 6133217526e7SJeff Layton nfs4_put_stid(&stp->st_stid); 6134217526e7SJeff Layton spin_lock(&nn->client_lock); 61351da177e4SLinus Torvalds } 6136217526e7SJeff Layton spin_unlock(&nn->client_lock); 6137217526e7SJeff Layton 61387919d0a2SJeff Layton /* 61397919d0a2SJeff Layton * It's possible for a client to try and acquire an already held lock 61407919d0a2SJeff Layton * that is being held for a long time, and then lose interest in it. 61417919d0a2SJeff Layton * So, we clean out any un-revisited request after a lease period 61427919d0a2SJeff Layton * under the assumption that the client is no longer interested. 61437919d0a2SJeff Layton * 61447919d0a2SJeff Layton * RFC5661, sec. 9.6 states that the client must not rely on getting 61457919d0a2SJeff Layton * notifications and must continue to poll for locks, even when the 61467919d0a2SJeff Layton * server supports them. Thus this shouldn't lead to clients blocking 61477919d0a2SJeff Layton * indefinitely once the lock does become free. 61487919d0a2SJeff Layton */ 61497919d0a2SJeff Layton BUG_ON(!list_empty(&reaplist)); 61500cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 61517919d0a2SJeff Layton while (!list_empty(&nn->blocked_locks_lru)) { 61527919d0a2SJeff Layton nbl = list_first_entry(&nn->blocked_locks_lru, 61537919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 61547f7e7a40SJ. Bruce Fields if (!state_expired(<, nbl->nbl_time)) 61557919d0a2SJeff Layton break; 61567919d0a2SJeff Layton list_move(&nbl->nbl_lru, &reaplist); 61577919d0a2SJeff Layton list_del_init(&nbl->nbl_list); 61587919d0a2SJeff Layton } 61590cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 61607919d0a2SJeff Layton 61617919d0a2SJeff Layton while (!list_empty(&reaplist)) { 616264ebe124SNaofumi Honda nbl = list_first_entry(&reaplist, 61637919d0a2SJeff Layton struct nfsd4_blocked_lock, nbl_lru); 61647919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 61657919d0a2SJeff Layton free_blocked_lock(nbl); 61667919d0a2SJeff Layton } 6167f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 6168f4e44b39SDai Ngo /* service the server-to-server copy delayed unmount list */ 6169f4e44b39SDai Ngo nfsd4_ssc_expire_umount(nn); 6170f4e44b39SDai Ngo #endif 617103f318caSJ. Bruce Fields out: 61727f7e7a40SJ. Bruce Fields return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); 61731da177e4SLinus Torvalds } 61741da177e4SLinus Torvalds 6175a254b246SHarvey Harrison static void laundromat_main(struct work_struct *); 6176a254b246SHarvey Harrison 6177a254b246SHarvey Harrison static void 617809121281SStanislav Kinsbursky laundromat_main(struct work_struct *laundry) 61791da177e4SLinus Torvalds { 618020b7d86fSArnd Bergmann time64_t t; 61812e55f3abSGeliang Tang struct delayed_work *dwork = to_delayed_work(laundry); 618209121281SStanislav Kinsbursky struct nfsd_net *nn = container_of(dwork, struct nfsd_net, 618309121281SStanislav Kinsbursky laundromat_work); 61841da177e4SLinus Torvalds 618509121281SStanislav Kinsbursky t = nfs4_laundromat(nn); 618609121281SStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); 61871da177e4SLinus Torvalds } 61881da177e4SLinus Torvalds 61897746b32fSDai Ngo static void 6190a1049eb4SDai Ngo courtesy_client_reaper(struct nfsd_net *nn) 61917746b32fSDai Ngo { 61927746b32fSDai Ngo struct list_head reaplist; 61937746b32fSDai Ngo 61947746b32fSDai Ngo nfs4_get_courtesy_client_reaplist(nn, &reaplist); 61957746b32fSDai Ngo nfs4_process_client_reaplist(&reaplist); 61967746b32fSDai Ngo } 61977746b32fSDai Ngo 6198a1049eb4SDai Ngo static void 619944df6f43SDai Ngo deleg_reaper(struct nfsd_net *nn) 620044df6f43SDai Ngo { 620144df6f43SDai Ngo struct list_head *pos, *next; 620244df6f43SDai Ngo struct nfs4_client *clp; 620344df6f43SDai Ngo struct list_head cblist; 620444df6f43SDai Ngo 620544df6f43SDai Ngo INIT_LIST_HEAD(&cblist); 620644df6f43SDai Ngo spin_lock(&nn->client_lock); 620744df6f43SDai Ngo list_for_each_safe(pos, next, &nn->client_lru) { 620844df6f43SDai Ngo clp = list_entry(pos, struct nfs4_client, cl_lru); 620944df6f43SDai Ngo if (clp->cl_state != NFSD4_ACTIVE || 621044df6f43SDai Ngo list_empty(&clp->cl_delegations) || 621144df6f43SDai Ngo atomic_read(&clp->cl_delegs_in_recall) || 621244df6f43SDai Ngo test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) || 621344df6f43SDai Ngo (ktime_get_boottime_seconds() - 621444df6f43SDai Ngo clp->cl_ra_time < 5)) { 621544df6f43SDai Ngo continue; 621644df6f43SDai Ngo } 621744df6f43SDai Ngo list_add(&clp->cl_ra_cblist, &cblist); 621844df6f43SDai Ngo 621944df6f43SDai Ngo /* release in nfsd4_cb_recall_any_release */ 622044df6f43SDai Ngo atomic_inc(&clp->cl_rpc_users); 622144df6f43SDai Ngo set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags); 622244df6f43SDai Ngo clp->cl_ra_time = ktime_get_boottime_seconds(); 622344df6f43SDai Ngo } 622444df6f43SDai Ngo spin_unlock(&nn->client_lock); 622544df6f43SDai Ngo 622644df6f43SDai Ngo while (!list_empty(&cblist)) { 622744df6f43SDai Ngo clp = list_first_entry(&cblist, struct nfs4_client, 622844df6f43SDai Ngo cl_ra_cblist); 622944df6f43SDai Ngo list_del_init(&clp->cl_ra_cblist); 623044df6f43SDai Ngo clp->cl_ra->ra_keep = 0; 623144df6f43SDai Ngo clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG); 6232638593beSDai Ngo trace_nfsd_cb_recall_any(clp->cl_ra); 623344df6f43SDai Ngo nfsd4_run_cb(&clp->cl_ra->ra_cb); 623444df6f43SDai Ngo } 623544df6f43SDai Ngo } 623644df6f43SDai Ngo 623744df6f43SDai Ngo static void 6238a1049eb4SDai Ngo nfsd4_state_shrinker_worker(struct work_struct *work) 6239a1049eb4SDai Ngo { 62407c24fa22SDai Ngo struct nfsd_net *nn = container_of(work, struct nfsd_net, 6241a1049eb4SDai Ngo nfsd_shrinker_work); 6242a1049eb4SDai Ngo 6243a1049eb4SDai Ngo courtesy_client_reaper(nn); 624444df6f43SDai Ngo deleg_reaper(nn); 6245a1049eb4SDai Ngo } 6246a1049eb4SDai Ngo 62478fcd461dSJeff Layton static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) 6248f8816512SNeilBrown { 62498fcd461dSJeff Layton if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) 6250f7a4d872SJ. Bruce Fields return nfserr_bad_stateid; 6251f7a4d872SJ. Bruce Fields return nfs_ok; 62521da177e4SLinus Torvalds } 62531da177e4SLinus Torvalds 62541da177e4SLinus Torvalds static 6255dcef0413SJ. Bruce Fields __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) 62561da177e4SLinus Torvalds { 6257b37ad28bSAl Viro __be32 status = nfserr_openmode; 62581da177e4SLinus Torvalds 625902921914SJ. Bruce Fields /* For lock stateid's, we test the parent open, not the lock: */ 626002921914SJ. Bruce Fields if (stp->st_openstp) 626102921914SJ. Bruce Fields stp = stp->st_openstp; 626282c5ff1bSJeff Layton if ((flags & WR_STATE) && !access_permit_write(stp)) 62631da177e4SLinus Torvalds goto out; 626482c5ff1bSJeff Layton if ((flags & RD_STATE) && !access_permit_read(stp)) 62651da177e4SLinus Torvalds goto out; 62661da177e4SLinus Torvalds status = nfs_ok; 62671da177e4SLinus Torvalds out: 62681da177e4SLinus Torvalds return status; 62691da177e4SLinus Torvalds } 62701da177e4SLinus Torvalds 6271b37ad28bSAl Viro static inline __be32 62725ccb0066SStanislav Kinsbursky check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) 62731da177e4SLinus Torvalds { 6274203a8c8eSJ. Bruce Fields if (ONE_STATEID(stateid) && (flags & RD_STATE)) 62751da177e4SLinus Torvalds return nfs_ok; 6276c87fb4a3SJ. Bruce Fields else if (opens_in_grace(net)) { 627725985edcSLucas De Marchi /* Answer in remaining cases depends on existence of 62781da177e4SLinus Torvalds * conflicting state; so we must wait out the grace period. */ 62791da177e4SLinus Torvalds return nfserr_grace; 62801da177e4SLinus Torvalds } else if (flags & WR_STATE) 62811da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 62821da177e4SLinus Torvalds NFS4_SHARE_DENY_WRITE); 62831da177e4SLinus Torvalds else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */ 62841da177e4SLinus Torvalds return nfs4_share_conflict(current_fh, 62851da177e4SLinus Torvalds NFS4_SHARE_DENY_READ); 62861da177e4SLinus Torvalds } 62871da177e4SLinus Torvalds 628857b7b43bSJ. Bruce Fields static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 62890836f587SJ. Bruce Fields { 62906668958fSAndy Adamson /* 62916668958fSAndy Adamson * When sessions are used the stateid generation number is ignored 62926668958fSAndy Adamson * when it is zero. 62936668958fSAndy Adamson */ 629428dde241SJ. Bruce Fields if (has_session && in->si_generation == 0) 629581b82965SJ. Bruce Fields return nfs_ok; 629681b82965SJ. Bruce Fields 629781b82965SJ. Bruce Fields if (in->si_generation == ref->si_generation) 629881b82965SJ. Bruce Fields return nfs_ok; 62996668958fSAndy Adamson 63000836f587SJ. Bruce Fields /* If the client sends us a stateid from the future, it's buggy: */ 630114b7f4a1SJeff Layton if (nfsd4_stateid_generation_after(in, ref)) 63020836f587SJ. Bruce Fields return nfserr_bad_stateid; 63030836f587SJ. Bruce Fields /* 630481b82965SJ. Bruce Fields * However, we could see a stateid from the past, even from a 630581b82965SJ. Bruce Fields * non-buggy client. For example, if the client sends a lock 630681b82965SJ. Bruce Fields * while some IO is outstanding, the lock may bump si_generation 630781b82965SJ. Bruce Fields * while the IO is still in flight. The client could avoid that 630881b82965SJ. Bruce Fields * situation by waiting for responses on all the IO requests, 630981b82965SJ. Bruce Fields * but better performance may result in retrying IO that 631081b82965SJ. Bruce Fields * receives an old_stateid error if requests are rarely 631181b82965SJ. Bruce Fields * reordered in flight: 63120836f587SJ. Bruce Fields */ 63130836f587SJ. Bruce Fields return nfserr_old_stateid; 63140836f587SJ. Bruce Fields } 63150836f587SJ. Bruce Fields 631603da3169STrond Myklebust static __be32 nfsd4_stid_check_stateid_generation(stateid_t *in, struct nfs4_stid *s, bool has_session) 631703da3169STrond Myklebust { 631803da3169STrond Myklebust __be32 ret; 631903da3169STrond Myklebust 632003da3169STrond Myklebust spin_lock(&s->sc_lock); 632103da3169STrond Myklebust ret = nfsd4_verify_open_stid(s); 632203da3169STrond Myklebust if (ret == nfs_ok) 632303da3169STrond Myklebust ret = check_stateid_generation(in, &s->sc_stateid, has_session); 632403da3169STrond Myklebust spin_unlock(&s->sc_lock); 632503da3169STrond Myklebust return ret; 632603da3169STrond Myklebust } 632703da3169STrond Myklebust 6328ebe9cb3bSChristoph Hellwig static __be32 nfsd4_check_openowner_confirmed(struct nfs4_ol_stateid *ols) 6329ebe9cb3bSChristoph Hellwig { 6330ebe9cb3bSChristoph Hellwig if (ols->st_stateowner->so_is_open_owner && 6331ebe9cb3bSChristoph Hellwig !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) 6332ebe9cb3bSChristoph Hellwig return nfserr_bad_stateid; 6333ebe9cb3bSChristoph Hellwig return nfs_ok; 6334ebe9cb3bSChristoph Hellwig } 6335ebe9cb3bSChristoph Hellwig 63367df302f7SChuck Lever static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) 633717456804SBryan Schumaker { 633897b7e3b6SJ. Bruce Fields struct nfs4_stid *s; 63391af71cc8SJeff Layton __be32 status = nfserr_bad_stateid; 634017456804SBryan Schumaker 6341ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 6342ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 63431af71cc8SJeff Layton return status; 63441af71cc8SJeff Layton spin_lock(&cl->cl_lock); 63451af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 634697b7e3b6SJ. Bruce Fields if (!s) 63471af71cc8SJeff Layton goto out_unlock; 634803da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 1); 634917456804SBryan Schumaker if (status) 63501af71cc8SJeff Layton goto out_unlock; 635123340032SJ. Bruce Fields switch (s->sc_type) { 635223340032SJ. Bruce Fields case NFS4_DELEG_STID: 63531af71cc8SJeff Layton status = nfs_ok; 63541af71cc8SJeff Layton break; 63553bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 63561af71cc8SJeff Layton status = nfserr_deleg_revoked; 63571af71cc8SJeff Layton break; 635823340032SJ. Bruce Fields case NFS4_OPEN_STID: 635923340032SJ. Bruce Fields case NFS4_LOCK_STID: 6360ebe9cb3bSChristoph Hellwig status = nfsd4_check_openowner_confirmed(openlockstateid(s)); 63611af71cc8SJeff Layton break; 636223340032SJ. Bruce Fields default: 636323340032SJ. Bruce Fields printk("unknown stateid type %x\n", s->sc_type); 6364df561f66SGustavo A. R. Silva fallthrough; 636523340032SJ. Bruce Fields case NFS4_CLOSED_STID: 6366b0fc29d6STrond Myklebust case NFS4_CLOSED_DELEG_STID: 63671af71cc8SJeff Layton status = nfserr_bad_stateid; 636823340032SJ. Bruce Fields } 63691af71cc8SJeff Layton out_unlock: 63701af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 63711af71cc8SJeff Layton return status; 637217456804SBryan Schumaker } 637317456804SBryan Schumaker 6374cd61c522SChristoph Hellwig __be32 63752dd6e458STrond Myklebust nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, 63762dd6e458STrond Myklebust stateid_t *stateid, unsigned char typemask, 63772dd6e458STrond Myklebust struct nfs4_stid **s, struct nfsd_net *nn) 637838c2f4b1SJ. Bruce Fields { 63790eb6f20aSJ. Bruce Fields __be32 status; 63804d01416aSJeff Layton struct nfs4_stid *stid; 638195da1b3aSAndrew Elble bool return_revoked = false; 638295da1b3aSAndrew Elble 638395da1b3aSAndrew Elble /* 638495da1b3aSAndrew Elble * only return revoked delegations if explicitly asked. 638595da1b3aSAndrew Elble * otherwise we report revoked or bad_stateid status. 638695da1b3aSAndrew Elble */ 638795da1b3aSAndrew Elble if (typemask & NFS4_REVOKED_DELEG_STID) 638895da1b3aSAndrew Elble return_revoked = true; 638995da1b3aSAndrew Elble else if (typemask & NFS4_DELEG_STID) 639095da1b3aSAndrew Elble typemask |= NFS4_REVOKED_DELEG_STID; 639138c2f4b1SJ. Bruce Fields 6392ae254dacSAndrew Elble if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || 6393ae254dacSAndrew Elble CLOSE_STATEID(stateid)) 639438c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 6395f71475baSJ. Bruce Fields status = set_client(&stateid->si_opaque.so_clid, cstate, nn); 6396a8a7c677STrond Myklebust if (status == nfserr_stale_clientid) { 63974b24ca7dSJeff Layton if (cstate->session) 6398a8a7c677STrond Myklebust return nfserr_bad_stateid; 639938c2f4b1SJ. Bruce Fields return nfserr_stale_stateid; 6400a8a7c677STrond Myklebust } 64010eb6f20aSJ. Bruce Fields if (status) 64020eb6f20aSJ. Bruce Fields return status; 64034d01416aSJeff Layton stid = find_stateid_by_type(cstate->clp, stateid, typemask); 64044d01416aSJeff Layton if (!stid) 640538c2f4b1SJ. Bruce Fields return nfserr_bad_stateid; 64064d01416aSJeff Layton if ((stid->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { 64074d01416aSJeff Layton nfs4_put_stid(stid); 640895da1b3aSAndrew Elble if (cstate->minorversion) 640995da1b3aSAndrew Elble return nfserr_deleg_revoked; 641095da1b3aSAndrew Elble return nfserr_bad_stateid; 641195da1b3aSAndrew Elble } 64124d01416aSJeff Layton *s = stid; 641338c2f4b1SJ. Bruce Fields return nfs_ok; 641438c2f4b1SJ. Bruce Fields } 641538c2f4b1SJ. Bruce Fields 6416eb82dd39SJeff Layton static struct nfsd_file * 6417a0649b2dSChristoph Hellwig nfs4_find_file(struct nfs4_stid *s, int flags) 6418a0649b2dSChristoph Hellwig { 6419bd6aaf78SJeff Layton struct nfsd_file *ret = NULL; 6420bd6aaf78SJeff Layton 6421af90f707SChristoph Hellwig if (!s) 6422af90f707SChristoph Hellwig return NULL; 6423af90f707SChristoph Hellwig 6424a0649b2dSChristoph Hellwig switch (s->sc_type) { 6425a0649b2dSChristoph Hellwig case NFS4_DELEG_STID: 6426bd6aaf78SJeff Layton spin_lock(&s->sc_file->fi_lock); 6427bd6aaf78SJeff Layton ret = nfsd_file_get(s->sc_file->fi_deleg_file); 6428bd6aaf78SJeff Layton spin_unlock(&s->sc_file->fi_lock); 6429bd6aaf78SJeff Layton break; 6430a0649b2dSChristoph Hellwig case NFS4_OPEN_STID: 6431a0649b2dSChristoph Hellwig case NFS4_LOCK_STID: 6432a0649b2dSChristoph Hellwig if (flags & RD_STATE) 6433bd6aaf78SJeff Layton ret = find_readable_file(s->sc_file); 6434a0649b2dSChristoph Hellwig else 6435bd6aaf78SJeff Layton ret = find_writeable_file(s->sc_file); 6436a0649b2dSChristoph Hellwig } 6437a0649b2dSChristoph Hellwig 6438bd6aaf78SJeff Layton return ret; 6439a0649b2dSChristoph Hellwig } 6440a0649b2dSChristoph Hellwig 6441a0649b2dSChristoph Hellwig static __be32 6442d8836f77SJ. Bruce Fields nfs4_check_olstateid(struct nfs4_ol_stateid *ols, int flags) 6443a0649b2dSChristoph Hellwig { 6444a0649b2dSChristoph Hellwig __be32 status; 6445a0649b2dSChristoph Hellwig 6446a0649b2dSChristoph Hellwig status = nfsd4_check_openowner_confirmed(ols); 6447a0649b2dSChristoph Hellwig if (status) 6448a0649b2dSChristoph Hellwig return status; 6449a0649b2dSChristoph Hellwig return nfs4_check_openmode(ols, flags); 6450a0649b2dSChristoph Hellwig } 6451a0649b2dSChristoph Hellwig 6452af90f707SChristoph Hellwig static __be32 6453af90f707SChristoph Hellwig nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, 64545c4583b2SJeff Layton struct nfsd_file **nfp, int flags) 6455af90f707SChristoph Hellwig { 6456af90f707SChristoph Hellwig int acc = (flags & RD_STATE) ? NFSD_MAY_READ : NFSD_MAY_WRITE; 6457eb82dd39SJeff Layton struct nfsd_file *nf; 6458af90f707SChristoph Hellwig __be32 status; 6459af90f707SChristoph Hellwig 6460eb82dd39SJeff Layton nf = nfs4_find_file(s, flags); 6461eb82dd39SJeff Layton if (nf) { 6462af90f707SChristoph Hellwig status = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, 6463af90f707SChristoph Hellwig acc | NFSD_MAY_OWNER_OVERRIDE); 64645c4583b2SJeff Layton if (status) { 64655c4583b2SJeff Layton nfsd_file_put(nf); 6466eb82dd39SJeff Layton goto out; 64675c4583b2SJeff Layton } 6468af90f707SChristoph Hellwig } else { 6469eb82dd39SJeff Layton status = nfsd_file_acquire(rqstp, fhp, acc, &nf); 6470af90f707SChristoph Hellwig if (status) 6471af90f707SChristoph Hellwig return status; 6472af90f707SChristoph Hellwig } 64735c4583b2SJeff Layton *nfp = nf; 6474eb82dd39SJeff Layton out: 6475eb82dd39SJeff Layton return status; 6476af90f707SChristoph Hellwig } 6477624322f1SOlga Kornievskaia static void 6478624322f1SOlga Kornievskaia _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 6479624322f1SOlga Kornievskaia { 6480781fde1aSChuck Lever WARN_ON_ONCE(cps->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID); 6481781fde1aSChuck Lever if (!refcount_dec_and_test(&cps->cp_stateid.cs_count)) 6482624322f1SOlga Kornievskaia return; 6483624322f1SOlga Kornievskaia list_del(&cps->cp_list); 6484624322f1SOlga Kornievskaia idr_remove(&nn->s2s_cp_stateids, 6485781fde1aSChuck Lever cps->cp_stateid.cs_stid.si_opaque.so_id); 6486624322f1SOlga Kornievskaia kfree(cps); 6487624322f1SOlga Kornievskaia } 6488b7342204SOlga Kornievskaia /* 6489b7342204SOlga Kornievskaia * A READ from an inter server to server COPY will have a 6490b7342204SOlga Kornievskaia * copy stateid. Look up the copy notify stateid from the 6491b7342204SOlga Kornievskaia * idr structure and take a reference on it. 6492b7342204SOlga Kornievskaia */ 6493ce0887acSOlga Kornievskaia __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st, 6494ce0887acSOlga Kornievskaia struct nfs4_client *clp, 6495b7342204SOlga Kornievskaia struct nfs4_cpntf_state **cps) 6496b7342204SOlga Kornievskaia { 6497b7342204SOlga Kornievskaia copy_stateid_t *cps_t; 6498b7342204SOlga Kornievskaia struct nfs4_cpntf_state *state = NULL; 6499b7342204SOlga Kornievskaia 6500b7342204SOlga Kornievskaia if (st->si_opaque.so_clid.cl_id != nn->s2s_cp_cl_id) 6501b7342204SOlga Kornievskaia return nfserr_bad_stateid; 6502b7342204SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6503b7342204SOlga Kornievskaia cps_t = idr_find(&nn->s2s_cp_stateids, st->si_opaque.so_id); 6504b7342204SOlga Kornievskaia if (cps_t) { 6505b7342204SOlga Kornievskaia state = container_of(cps_t, struct nfs4_cpntf_state, 6506b7342204SOlga Kornievskaia cp_stateid); 6507781fde1aSChuck Lever if (state->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID) { 65085277a79eSDan Carpenter state = NULL; 65095277a79eSDan Carpenter goto unlock; 65105277a79eSDan Carpenter } 6511ce0887acSOlga Kornievskaia if (!clp) 6512781fde1aSChuck Lever refcount_inc(&state->cp_stateid.cs_count); 6513ce0887acSOlga Kornievskaia else 6514ce0887acSOlga Kornievskaia _free_cpntf_state_locked(nn, state); 6515b7342204SOlga Kornievskaia } 65165277a79eSDan Carpenter unlock: 6517b7342204SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 6518b7342204SOlga Kornievskaia if (!state) 6519b7342204SOlga Kornievskaia return nfserr_bad_stateid; 6520ce0887acSOlga Kornievskaia if (!clp && state) 6521b7342204SOlga Kornievskaia *cps = state; 6522b7342204SOlga Kornievskaia return 0; 6523b7342204SOlga Kornievskaia } 6524b7342204SOlga Kornievskaia 6525b7342204SOlga Kornievskaia static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, 6526b7342204SOlga Kornievskaia struct nfs4_stid **stid) 6527b7342204SOlga Kornievskaia { 6528b7342204SOlga Kornievskaia __be32 status; 6529b7342204SOlga Kornievskaia struct nfs4_cpntf_state *cps = NULL; 653047fdb22dSJ. Bruce Fields struct nfs4_client *found; 6531b7342204SOlga Kornievskaia 6532ce0887acSOlga Kornievskaia status = manage_cpntf_state(nn, st, NULL, &cps); 6533b7342204SOlga Kornievskaia if (status) 6534b7342204SOlga Kornievskaia return status; 6535b7342204SOlga Kornievskaia 653620b7d86fSArnd Bergmann cps->cpntf_time = ktime_get_boottime_seconds(); 653747fdb22dSJ. Bruce Fields 653847fdb22dSJ. Bruce Fields status = nfserr_expired; 653947fdb22dSJ. Bruce Fields found = lookup_clientid(&cps->cp_p_clid, true, nn); 654047fdb22dSJ. Bruce Fields if (!found) 6541b7342204SOlga Kornievskaia goto out; 654247fdb22dSJ. Bruce Fields 654347fdb22dSJ. Bruce Fields *stid = find_stateid_by_type(found, &cps->cp_p_stateid, 654447fdb22dSJ. Bruce Fields NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID); 654547fdb22dSJ. Bruce Fields if (*stid) 654647fdb22dSJ. Bruce Fields status = nfs_ok; 654747fdb22dSJ. Bruce Fields else 654847fdb22dSJ. Bruce Fields status = nfserr_bad_stateid; 654947fdb22dSJ. Bruce Fields 655047fdb22dSJ. Bruce Fields put_client_renew(found); 6551b7342204SOlga Kornievskaia out: 6552b7342204SOlga Kornievskaia nfs4_put_cpntf_state(nn, cps); 6553b7342204SOlga Kornievskaia return status; 6554b7342204SOlga Kornievskaia } 6555624322f1SOlga Kornievskaia 6556624322f1SOlga Kornievskaia void nfs4_put_cpntf_state(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) 6557624322f1SOlga Kornievskaia { 6558624322f1SOlga Kornievskaia spin_lock(&nn->s2s_cp_lock); 6559624322f1SOlga Kornievskaia _free_cpntf_state_locked(nn, cps); 6560624322f1SOlga Kornievskaia spin_unlock(&nn->s2s_cp_lock); 6561624322f1SOlga Kornievskaia } 6562af90f707SChristoph Hellwig 6563ee97e730SJeff Layton /** 6564ee97e730SJeff Layton * nfs4_preprocess_stateid_op - find and prep stateid for an operation 6565ee97e730SJeff Layton * @rqstp: incoming request from client 6566ee97e730SJeff Layton * @cstate: current compound state 6567ee97e730SJeff Layton * @fhp: filehandle associated with requested stateid 6568ee97e730SJeff Layton * @stateid: stateid (provided by client) 6569ee97e730SJeff Layton * @flags: flags describing type of operation to be done 6570ee97e730SJeff Layton * @nfp: optional nfsd_file return pointer (may be NULL) 6571ee97e730SJeff Layton * @cstid: optional returned nfs4_stid pointer (may be NULL) 6572ee97e730SJeff Layton * 6573ee97e730SJeff Layton * Given info from the client, look up a nfs4_stid for the operation. On 6574ee97e730SJeff Layton * success, it returns a reference to the nfs4_stid and/or the nfsd_file 6575ee97e730SJeff Layton * associated with it. 65761da177e4SLinus Torvalds */ 6577b37ad28bSAl Viro __be32 6578af90f707SChristoph Hellwig nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 6579aa0d6aedSAnna Schumaker struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 6580624322f1SOlga Kornievskaia stateid_t *stateid, int flags, struct nfsd_file **nfp, 6581624322f1SOlga Kornievskaia struct nfs4_stid **cstid) 65821da177e4SLinus Torvalds { 6583af90f707SChristoph Hellwig struct net *net = SVC_NET(rqstp); 65843320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 6585af90f707SChristoph Hellwig struct nfs4_stid *s = NULL; 6586b37ad28bSAl Viro __be32 status; 65871da177e4SLinus Torvalds 65885c4583b2SJeff Layton if (nfp) 65895c4583b2SJeff Layton *nfp = NULL; 65901da177e4SLinus Torvalds 6591af90f707SChristoph Hellwig if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { 6592074b07d9SJ. Bruce Fields if (cstid) 6593074b07d9SJ. Bruce Fields status = nfserr_bad_stateid; 6594074b07d9SJ. Bruce Fields else 6595074b07d9SJ. Bruce Fields status = check_special_stateids(net, fhp, stateid, 6596074b07d9SJ. Bruce Fields flags); 6597af90f707SChristoph Hellwig goto done; 6598af90f707SChristoph Hellwig } 65991da177e4SLinus Torvalds 66002dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, 6601db24b3b4SJeff Layton NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, 66022dd6e458STrond Myklebust &s, nn); 6603b7342204SOlga Kornievskaia if (status == nfserr_bad_stateid) 6604b7342204SOlga Kornievskaia status = find_cpntf_state(nn, stateid, &s); 660538c2f4b1SJ. Bruce Fields if (status) 6606c2d1d6a8STrond Myklebust return status; 660703da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, s, 6608a0649b2dSChristoph Hellwig nfsd4_has_session(cstate)); 66090c2a498fSJ. Bruce Fields if (status) 66100c2a498fSJ. Bruce Fields goto out; 6611a0649b2dSChristoph Hellwig 6612f7a4d872SJ. Bruce Fields switch (s->sc_type) { 6613f7a4d872SJ. Bruce Fields case NFS4_DELEG_STID: 6614a0649b2dSChristoph Hellwig status = nfs4_check_delegmode(delegstateid(s), flags); 6615f7a4d872SJ. Bruce Fields break; 6616f7a4d872SJ. Bruce Fields case NFS4_OPEN_STID: 6617f7a4d872SJ. Bruce Fields case NFS4_LOCK_STID: 6618d8836f77SJ. Bruce Fields status = nfs4_check_olstateid(openlockstateid(s), flags); 6619f7a4d872SJ. Bruce Fields break; 6620f7a4d872SJ. Bruce Fields default: 662114bcab1aSTrond Myklebust status = nfserr_bad_stateid; 6622a0649b2dSChristoph Hellwig break; 66231da177e4SLinus Torvalds } 66248fcd461dSJeff Layton if (status) 66258fcd461dSJeff Layton goto out; 66268fcd461dSJeff Layton status = nfs4_check_fh(fhp, s); 6627a0649b2dSChristoph Hellwig 6628af90f707SChristoph Hellwig done: 66295c4583b2SJeff Layton if (status == nfs_ok && nfp) 66305c4583b2SJeff Layton status = nfs4_check_file(rqstp, fhp, s, nfp, flags); 66311da177e4SLinus Torvalds out: 6632624322f1SOlga Kornievskaia if (s) { 6633624322f1SOlga Kornievskaia if (!status && cstid) 6634624322f1SOlga Kornievskaia *cstid = s; 6635624322f1SOlga Kornievskaia else 6636fd911011STrond Myklebust nfs4_put_stid(s); 6637624322f1SOlga Kornievskaia } 66381da177e4SLinus Torvalds return status; 66391da177e4SLinus Torvalds } 66401da177e4SLinus Torvalds 6641e1ca12dfSBryan Schumaker /* 664217456804SBryan Schumaker * Test if the stateid is valid 664317456804SBryan Schumaker */ 664417456804SBryan Schumaker __be32 664517456804SBryan Schumaker nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6646eb69853dSChristoph Hellwig union nfsd4_op_u *u) 664717456804SBryan Schumaker { 6648eb69853dSChristoph Hellwig struct nfsd4_test_stateid *test_stateid = &u->test_stateid; 664903cfb420SBryan Schumaker struct nfsd4_test_stateid_id *stateid; 6650ec59659bSJ. Bruce Fields struct nfs4_client *cl = cstate->clp; 665103cfb420SBryan Schumaker 665203cfb420SBryan Schumaker list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) 66537df302f7SChuck Lever stateid->ts_id_status = 66547df302f7SChuck Lever nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); 665503cfb420SBryan Schumaker 665617456804SBryan Schumaker return nfs_ok; 665717456804SBryan Schumaker } 665817456804SBryan Schumaker 665942691398SChuck Lever static __be32 666042691398SChuck Lever nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s) 666142691398SChuck Lever { 666242691398SChuck Lever struct nfs4_ol_stateid *stp = openlockstateid(s); 666342691398SChuck Lever __be32 ret; 666442691398SChuck Lever 6665659aefb6STrond Myklebust ret = nfsd4_lock_ol_stateid(stp); 6666659aefb6STrond Myklebust if (ret) 6667659aefb6STrond Myklebust goto out_put_stid; 666842691398SChuck Lever 666942691398SChuck Lever ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 667042691398SChuck Lever if (ret) 667142691398SChuck Lever goto out; 667242691398SChuck Lever 667342691398SChuck Lever ret = nfserr_locks_held; 667442691398SChuck Lever if (check_for_locks(stp->st_stid.sc_file, 667542691398SChuck Lever lockowner(stp->st_stateowner))) 667642691398SChuck Lever goto out; 667742691398SChuck Lever 667842691398SChuck Lever release_lock_stateid(stp); 667942691398SChuck Lever ret = nfs_ok; 668042691398SChuck Lever 668142691398SChuck Lever out: 668242691398SChuck Lever mutex_unlock(&stp->st_mutex); 6683659aefb6STrond Myklebust out_put_stid: 668442691398SChuck Lever nfs4_put_stid(s); 668542691398SChuck Lever return ret; 668642691398SChuck Lever } 668742691398SChuck Lever 6688e1ca12dfSBryan Schumaker __be32 6689e1ca12dfSBryan Schumaker nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6690eb69853dSChristoph Hellwig union nfsd4_op_u *u) 6691e1ca12dfSBryan Schumaker { 6692eb69853dSChristoph Hellwig struct nfsd4_free_stateid *free_stateid = &u->free_stateid; 6693e1ca12dfSBryan Schumaker stateid_t *stateid = &free_stateid->fr_stateid; 66942da1cec7SJ. Bruce Fields struct nfs4_stid *s; 66953bd64a5bSJ. Bruce Fields struct nfs4_delegation *dp; 6696ec59659bSJ. Bruce Fields struct nfs4_client *cl = cstate->clp; 66972da1cec7SJ. Bruce Fields __be32 ret = nfserr_bad_stateid; 6698e1ca12dfSBryan Schumaker 66991af71cc8SJeff Layton spin_lock(&cl->cl_lock); 67001af71cc8SJeff Layton s = find_stateid_locked(cl, stateid); 67012da1cec7SJ. Bruce Fields if (!s) 67021af71cc8SJeff Layton goto out_unlock; 670303da3169STrond Myklebust spin_lock(&s->sc_lock); 67042da1cec7SJ. Bruce Fields switch (s->sc_type) { 67052da1cec7SJ. Bruce Fields case NFS4_DELEG_STID: 6706e1ca12dfSBryan Schumaker ret = nfserr_locks_held; 67071af71cc8SJeff Layton break; 67082da1cec7SJ. Bruce Fields case NFS4_OPEN_STID: 67091af71cc8SJeff Layton ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 67101af71cc8SJeff Layton if (ret) 67111af71cc8SJeff Layton break; 67121af71cc8SJeff Layton ret = nfserr_locks_held; 67131af71cc8SJeff Layton break; 67142da1cec7SJ. Bruce Fields case NFS4_LOCK_STID: 671503da3169STrond Myklebust spin_unlock(&s->sc_lock); 6716a15dfcd5SElena Reshetova refcount_inc(&s->sc_count); 67171af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 671842691398SChuck Lever ret = nfsd4_free_lock_stateid(stateid, s); 67191af71cc8SJeff Layton goto out; 67203bd64a5bSJ. Bruce Fields case NFS4_REVOKED_DELEG_STID: 672103da3169STrond Myklebust spin_unlock(&s->sc_lock); 67223bd64a5bSJ. Bruce Fields dp = delegstateid(s); 67232d4a532dSJeff Layton list_del_init(&dp->dl_recall_lru); 67242d4a532dSJeff Layton spin_unlock(&cl->cl_lock); 67256011695dSTrond Myklebust nfs4_put_stid(s); 67263bd64a5bSJ. Bruce Fields ret = nfs_ok; 67271af71cc8SJeff Layton goto out; 67281af71cc8SJeff Layton /* Default falls through and returns nfserr_bad_stateid */ 6729e1ca12dfSBryan Schumaker } 673003da3169STrond Myklebust spin_unlock(&s->sc_lock); 67311af71cc8SJeff Layton out_unlock: 67321af71cc8SJeff Layton spin_unlock(&cl->cl_lock); 6733e1ca12dfSBryan Schumaker out: 6734e1ca12dfSBryan Schumaker return ret; 6735e1ca12dfSBryan Schumaker } 6736e1ca12dfSBryan Schumaker 67374c4cd222SNeilBrown static inline int 67384c4cd222SNeilBrown setlkflg (int type) 67394c4cd222SNeilBrown { 67404c4cd222SNeilBrown return (type == NFS4_READW_LT || type == NFS4_READ_LT) ? 67414c4cd222SNeilBrown RD_STATE : WR_STATE; 67424c4cd222SNeilBrown } 67431da177e4SLinus Torvalds 6744dcef0413SJ. Bruce Fields static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) 6745c0a5d93eSJ. Bruce Fields { 6746c0a5d93eSJ. Bruce Fields struct svc_fh *current_fh = &cstate->current_fh; 6747c0a5d93eSJ. Bruce Fields struct nfs4_stateowner *sop = stp->st_stateowner; 6748c0a5d93eSJ. Bruce Fields __be32 status; 6749c0a5d93eSJ. Bruce Fields 6750c0a5d93eSJ. Bruce Fields status = nfsd4_check_seqid(cstate, sop, seqid); 6751c0a5d93eSJ. Bruce Fields if (status) 6752c0a5d93eSJ. Bruce Fields return status; 67539271d7e5STrond Myklebust status = nfsd4_lock_ol_stateid(stp); 67549271d7e5STrond Myklebust if (status != nfs_ok) 67559271d7e5STrond Myklebust return status; 6756f7a4d872SJ. Bruce Fields status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 675735a92fe8SJeff Layton if (status == nfs_ok) 675835a92fe8SJeff Layton status = nfs4_check_fh(current_fh, &stp->st_stid); 675935a92fe8SJeff Layton if (status != nfs_ok) 6760feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6761f7a4d872SJ. Bruce Fields return status; 6762c0a5d93eSJ. Bruce Fields } 6763c0a5d93eSJ. Bruce Fields 6764ee97e730SJeff Layton /** 6765ee97e730SJeff Layton * nfs4_preprocess_seqid_op - find and prep an ol_stateid for a seqid-morphing op 6766ee97e730SJeff Layton * @cstate: compund state 6767ee97e730SJeff Layton * @seqid: seqid (provided by client) 6768ee97e730SJeff Layton * @stateid: stateid (provided by client) 6769ee97e730SJeff Layton * @typemask: mask of allowable types for this operation 6770ee97e730SJeff Layton * @stpp: return pointer for the stateid found 6771ee97e730SJeff Layton * @nn: net namespace for request 6772ee97e730SJeff Layton * 6773ee97e730SJeff Layton * Given a stateid+seqid from a client, look up an nfs4_ol_stateid and 6774ee97e730SJeff Layton * return it in @stpp. On a nfs_ok return, the returned stateid will 6775ee97e730SJeff Layton * have its st_mutex locked. 67761da177e4SLinus Torvalds */ 6777b37ad28bSAl Viro static __be32 6778dd453dfdSBenny Halevy nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 67792288d0e3SJ. Bruce Fields stateid_t *stateid, char typemask, 67803320fef1SStanislav Kinsbursky struct nfs4_ol_stateid **stpp, 67813320fef1SStanislav Kinsbursky struct nfsd_net *nn) 67821da177e4SLinus Torvalds { 67830836f587SJ. Bruce Fields __be32 status; 678438c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 6785e17f99b7STrond Myklebust struct nfs4_ol_stateid *stp = NULL; 67861da177e4SLinus Torvalds 6787dd5e3fbcSChuck Lever trace_nfsd_preprocess(seqid, stateid); 67881da177e4SLinus Torvalds 67891da177e4SLinus Torvalds *stpp = NULL; 67902dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, typemask, &s, nn); 6791c0a5d93eSJ. Bruce Fields if (status) 6792c0a5d93eSJ. Bruce Fields return status; 6793e17f99b7STrond Myklebust stp = openlockstateid(s); 679458fb12e6SJeff Layton nfsd4_cstate_assign_replay(cstate, stp->st_stateowner); 67951da177e4SLinus Torvalds 6796e17f99b7STrond Myklebust status = nfs4_seqid_op_checks(cstate, stateid, seqid, stp); 6797fd911011STrond Myklebust if (!status) 6798e17f99b7STrond Myklebust *stpp = stp; 6799fd911011STrond Myklebust else 6800fd911011STrond Myklebust nfs4_put_stid(&stp->st_stid); 6801e17f99b7STrond Myklebust return status; 68021da177e4SLinus Torvalds } 68031da177e4SLinus Torvalds 68043320fef1SStanislav Kinsbursky static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, 68053320fef1SStanislav Kinsbursky stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) 6806c0a5d93eSJ. Bruce Fields { 6807c0a5d93eSJ. Bruce Fields __be32 status; 6808c0a5d93eSJ. Bruce Fields struct nfs4_openowner *oo; 68094cbfc9f7STrond Myklebust struct nfs4_ol_stateid *stp; 68101da177e4SLinus Torvalds 6811c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, 68124cbfc9f7STrond Myklebust NFS4_OPEN_STID, &stp, nn); 68130836f587SJ. Bruce Fields if (status) 68140836f587SJ. Bruce Fields return status; 68154cbfc9f7STrond Myklebust oo = openowner(stp->st_stateowner); 68164cbfc9f7STrond Myklebust if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 6817feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 68184cbfc9f7STrond Myklebust nfs4_put_stid(&stp->st_stid); 6819c0a5d93eSJ. Bruce Fields return nfserr_bad_stateid; 68204cbfc9f7STrond Myklebust } 68214cbfc9f7STrond Myklebust *stpp = stp; 68223a4f98bbSNeilBrown return nfs_ok; 68231da177e4SLinus Torvalds } 68241da177e4SLinus Torvalds 6825b37ad28bSAl Viro __be32 6826ca364317SJ.Bruce Fields nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6827eb69853dSChristoph Hellwig union nfsd4_op_u *u) 68281da177e4SLinus Torvalds { 6829eb69853dSChristoph Hellwig struct nfsd4_open_confirm *oc = &u->open_confirm; 6830b37ad28bSAl Viro __be32 status; 6831fe0750e5SJ. Bruce Fields struct nfs4_openowner *oo; 6832dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 68333320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 68341da177e4SLinus Torvalds 6835a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_confirm on file %pd\n", 6836a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 68371da177e4SLinus Torvalds 6838ca364317SJ.Bruce Fields status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); 6839a8cddc5dSJ. Bruce Fields if (status) 6840a8cddc5dSJ. Bruce Fields return status; 68411da177e4SLinus Torvalds 68429072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, 6843ca364317SJ.Bruce Fields oc->oc_seqid, &oc->oc_req_stateid, 68443320fef1SStanislav Kinsbursky NFS4_OPEN_STID, &stp, nn); 68459072d5c6SJ. Bruce Fields if (status) 68461da177e4SLinus Torvalds goto out; 6847fe0750e5SJ. Bruce Fields oo = openowner(stp->st_stateowner); 684868b66e82SJ. Bruce Fields status = nfserr_bad_stateid; 684935a92fe8SJeff Layton if (oo->oo_flags & NFS4_OO_CONFIRMED) { 6850feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 68512585fc79STrond Myklebust goto put_stateid; 685235a92fe8SJeff Layton } 6853dad1c067SJ. Bruce Fields oo->oo_flags |= NFS4_OO_CONFIRMED; 68549767feb2SJeff Layton nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 6855feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 6856dd5e3fbcSChuck Lever trace_nfsd_open_confirm(oc->oc_seqid, &stp->st_stid.sc_stateid); 68572a4317c5SJeff Layton nfsd4_client_record_create(oo->oo_owner.so_client); 685868b66e82SJ. Bruce Fields status = nfs_ok; 68592585fc79STrond Myklebust put_stateid: 68602585fc79STrond Myklebust nfs4_put_stid(&stp->st_stid); 68611da177e4SLinus Torvalds out: 68629411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 68631da177e4SLinus Torvalds return status; 68641da177e4SLinus Torvalds } 68651da177e4SLinus Torvalds 68666409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) 68671da177e4SLinus Torvalds { 686882c5ff1bSJeff Layton if (!test_access(access, stp)) 68696409a5a6SJ. Bruce Fields return; 687011b9164aSTrond Myklebust nfs4_file_put_access(stp->st_stid.sc_file, access); 687182c5ff1bSJeff Layton clear_access(access, stp); 6872f197c271SJ. Bruce Fields } 68736409a5a6SJ. Bruce Fields 68746409a5a6SJ. Bruce Fields static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) 68756409a5a6SJ. Bruce Fields { 68766409a5a6SJ. Bruce Fields switch (to_access) { 68776409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_READ: 68786409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); 68796409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 68806409a5a6SJ. Bruce Fields break; 68816409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_WRITE: 68826409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); 68836409a5a6SJ. Bruce Fields nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); 68846409a5a6SJ. Bruce Fields break; 68856409a5a6SJ. Bruce Fields case NFS4_SHARE_ACCESS_BOTH: 68866409a5a6SJ. Bruce Fields break; 68876409a5a6SJ. Bruce Fields default: 6888063b0fb9SJ. Bruce Fields WARN_ON_ONCE(1); 68891da177e4SLinus Torvalds } 68901da177e4SLinus Torvalds } 68911da177e4SLinus Torvalds 6892b37ad28bSAl Viro __be32 6893ca364317SJ.Bruce Fields nfsd4_open_downgrade(struct svc_rqst *rqstp, 6894eb69853dSChristoph Hellwig struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) 68951da177e4SLinus Torvalds { 6896eb69853dSChristoph Hellwig struct nfsd4_open_downgrade *od = &u->open_downgrade; 6897b37ad28bSAl Viro __be32 status; 6898dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 68993320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 69001da177e4SLinus Torvalds 6901a6a9f18fSAl Viro dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", 6902a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 69031da177e4SLinus Torvalds 6904c30e92dfSJ. Bruce Fields /* We don't yet support WANT bits: */ 69052c8bd7e0SBenny Halevy if (od->od_deleg_want) 69062c8bd7e0SBenny Halevy dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, 69072c8bd7e0SBenny Halevy od->od_deleg_want); 69081da177e4SLinus Torvalds 6909c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, 69103320fef1SStanislav Kinsbursky &od->od_stateid, &stp, nn); 69119072d5c6SJ. Bruce Fields if (status) 69121da177e4SLinus Torvalds goto out; 69131da177e4SLinus Torvalds status = nfserr_inval; 691482c5ff1bSJeff Layton if (!test_access(od->od_share_access, stp)) { 6915c11c591fSJeff Layton dprintk("NFSD: access not a subset of current bitmap: 0x%hhx, input access=%08x\n", 69161da177e4SLinus Torvalds stp->st_access_bmap, od->od_share_access); 69170667b1e9STrond Myklebust goto put_stateid; 69181da177e4SLinus Torvalds } 6919ce0fc43cSJeff Layton if (!test_deny(od->od_share_deny, stp)) { 6920c11c591fSJeff Layton dprintk("NFSD: deny not a subset of current bitmap: 0x%hhx, input deny=%08x\n", 69211da177e4SLinus Torvalds stp->st_deny_bmap, od->od_share_deny); 69220667b1e9STrond Myklebust goto put_stateid; 69231da177e4SLinus Torvalds } 69246409a5a6SJ. Bruce Fields nfs4_stateid_downgrade(stp, od->od_share_access); 6925ce0fc43cSJeff Layton reset_union_bmap_deny(od->od_share_deny, stp); 69269767feb2SJeff Layton nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 69271da177e4SLinus Torvalds status = nfs_ok; 69280667b1e9STrond Myklebust put_stateid: 6929feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 69300667b1e9STrond Myklebust nfs4_put_stid(&stp->st_stid); 69311da177e4SLinus Torvalds out: 69329411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 69331da177e4SLinus Torvalds return status; 69341da177e4SLinus Torvalds } 69351da177e4SLinus Torvalds 6936f7a4d872SJ. Bruce Fields static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) 6937f7a4d872SJ. Bruce Fields { 6938acf9295bSTrond Myklebust struct nfs4_client *clp = s->st_stid.sc_client; 6939e8568739SJeff Layton bool unhashed; 6940d83017f9SJeff Layton LIST_HEAD(reaplist); 6941019805feSDai Ngo struct nfs4_ol_stateid *stp; 6942acf9295bSTrond Myklebust 69432c41beb0SJeff Layton spin_lock(&clp->cl_lock); 6944e8568739SJeff Layton unhashed = unhash_open_stateid(s, &reaplist); 6945acf9295bSTrond Myklebust 6946d83017f9SJeff Layton if (clp->cl_minorversion) { 6947e8568739SJeff Layton if (unhashed) 6948d83017f9SJeff Layton put_ol_stateid_locked(s, &reaplist); 6949d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6950019805feSDai Ngo list_for_each_entry(stp, &reaplist, st_locks) 6951019805feSDai Ngo nfs4_free_cpntf_statelist(clp->net, &stp->st_stid); 6952d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6953d83017f9SJeff Layton } else { 6954d83017f9SJeff Layton spin_unlock(&clp->cl_lock); 6955d83017f9SJeff Layton free_ol_stateid_reaplist(&reaplist); 6956e8568739SJeff Layton if (unhashed) 6957d3134b10SJeff Layton move_to_close_lru(s, clp->net); 695838c387b5SJ. Bruce Fields } 6959d83017f9SJeff Layton } 696038c387b5SJ. Bruce Fields 69611da177e4SLinus Torvalds /* 69621da177e4SLinus Torvalds * nfs4_unlock_state() called after encode 69631da177e4SLinus Torvalds */ 6964b37ad28bSAl Viro __be32 6965ca364317SJ.Bruce Fields nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 6966eb69853dSChristoph Hellwig union nfsd4_op_u *u) 69671da177e4SLinus Torvalds { 6968eb69853dSChristoph Hellwig struct nfsd4_close *close = &u->close; 6969b37ad28bSAl Viro __be32 status; 6970dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 69713320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 69723320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 69731da177e4SLinus Torvalds 6974a6a9f18fSAl Viro dprintk("NFSD: nfsd4_close on file %pd\n", 6975a6a9f18fSAl Viro cstate->current_fh.fh_dentry); 69761da177e4SLinus Torvalds 6977f7a4d872SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, 6978f7a4d872SJ. Bruce Fields &close->cl_stateid, 6979f7a4d872SJ. Bruce Fields NFS4_OPEN_STID|NFS4_CLOSED_STID, 69803320fef1SStanislav Kinsbursky &stp, nn); 69819411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 69829072d5c6SJ. Bruce Fields if (status) 69831da177e4SLinus Torvalds goto out; 698415ca08d3STrond Myklebust 698515ca08d3STrond Myklebust stp->st_stid.sc_type = NFS4_CLOSED_STID; 6986bd2decacSJeff Layton 6987bd2decacSJeff Layton /* 6988bd2decacSJeff Layton * Technically we don't _really_ have to increment or copy it, since 6989bd2decacSJeff Layton * it should just be gone after this operation and we clobber the 6990bd2decacSJeff Layton * copied value below, but we continue to do so here just to ensure 6991bd2decacSJeff Layton * that racing ops see that there was a state change. 6992bd2decacSJeff Layton */ 69939767feb2SJeff Layton nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 69941da177e4SLinus Torvalds 6995f7a4d872SJ. Bruce Fields nfsd4_close_open_stateid(stp); 699615ca08d3STrond Myklebust mutex_unlock(&stp->st_mutex); 69978a0b589dSTrond Myklebust 6998bd2decacSJeff Layton /* v4.1+ suggests that we send a special stateid in here, since the 6999bd2decacSJeff Layton * clients should just ignore this anyway. Since this is not useful 7000bd2decacSJeff Layton * for v4.0 clients either, we set it to the special close_stateid 7001bd2decacSJeff Layton * universally. 7002bd2decacSJeff Layton * 7003bd2decacSJeff Layton * See RFC5661 section 18.2.4, and RFC7530 section 16.2.5 7004bd2decacSJeff Layton */ 7005bd2decacSJeff Layton memcpy(&close->cl_stateid, &close_stateid, sizeof(close->cl_stateid)); 7006fb500a7cSTrond Myklebust 70078a0b589dSTrond Myklebust /* put reference from nfs4_preprocess_seqid_op */ 70088a0b589dSTrond Myklebust nfs4_put_stid(&stp->st_stid); 70091da177e4SLinus Torvalds out: 70101da177e4SLinus Torvalds return status; 70111da177e4SLinus Torvalds } 70121da177e4SLinus Torvalds 7013b37ad28bSAl Viro __be32 7014ca364317SJ.Bruce Fields nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7015eb69853dSChristoph Hellwig union nfsd4_op_u *u) 70161da177e4SLinus Torvalds { 7017eb69853dSChristoph Hellwig struct nfsd4_delegreturn *dr = &u->delegreturn; 7018203a8c8eSJ. Bruce Fields struct nfs4_delegation *dp; 7019203a8c8eSJ. Bruce Fields stateid_t *stateid = &dr->dr_stateid; 702038c2f4b1SJ. Bruce Fields struct nfs4_stid *s; 7021b37ad28bSAl Viro __be32 status; 70223320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 70231da177e4SLinus Torvalds 7024ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 7025203a8c8eSJ. Bruce Fields return status; 70261da177e4SLinus Torvalds 70272dd6e458STrond Myklebust status = nfsd4_lookup_stateid(cstate, stateid, NFS4_DELEG_STID, &s, nn); 702838c2f4b1SJ. Bruce Fields if (status) 7029203a8c8eSJ. Bruce Fields goto out; 703038c2f4b1SJ. Bruce Fields dp = delegstateid(s); 703103da3169STrond Myklebust status = nfsd4_stid_check_stateid_generation(stateid, &dp->dl_stid, nfsd4_has_session(cstate)); 7032203a8c8eSJ. Bruce Fields if (status) 7033fd911011STrond Myklebust goto put_stateid; 7034203a8c8eSJ. Bruce Fields 703520eee313SChuck Lever trace_nfsd_deleg_return(stateid); 7036c035362eSChuck Lever wake_up_var(d_inode(cstate->current_fh.fh_dentry)); 70373bd64a5bSJ. Bruce Fields destroy_delegation(dp); 7038fd911011STrond Myklebust put_stateid: 7039fd911011STrond Myklebust nfs4_put_stid(&dp->dl_stid); 70401da177e4SLinus Torvalds out: 70411da177e4SLinus Torvalds return status; 70421da177e4SLinus Torvalds } 70431da177e4SLinus Torvalds 704487df4de8SBenny Halevy /* last octet in a range */ 704587df4de8SBenny Halevy static inline u64 704687df4de8SBenny Halevy last_byte_offset(u64 start, u64 len) 704787df4de8SBenny Halevy { 704887df4de8SBenny Halevy u64 end; 704987df4de8SBenny Halevy 7050063b0fb9SJ. Bruce Fields WARN_ON_ONCE(!len); 705187df4de8SBenny Halevy end = start + len; 705287df4de8SBenny Halevy return end > start ? end - 1: NFS4_MAX_UINT64; 705387df4de8SBenny Halevy } 705487df4de8SBenny Halevy 70551da177e4SLinus Torvalds /* 70561da177e4SLinus Torvalds * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that 70571da177e4SLinus Torvalds * we can't properly handle lock requests that go beyond the (2^63 - 1)-th 70581da177e4SLinus Torvalds * byte, because of sign extension problems. Since NFSv4 calls for 64-bit 70591da177e4SLinus Torvalds * locking, this prevents us from being completely protocol-compliant. The 70601da177e4SLinus Torvalds * real solution to this problem is to start using unsigned file offsets in 70611da177e4SLinus Torvalds * the VFS, but this is a very deep change! 70621da177e4SLinus Torvalds */ 70631da177e4SLinus Torvalds static inline void 70641da177e4SLinus Torvalds nfs4_transform_lock_offset(struct file_lock *lock) 70651da177e4SLinus Torvalds { 70661da177e4SLinus Torvalds if (lock->fl_start < 0) 70671da177e4SLinus Torvalds lock->fl_start = OFFSET_MAX; 70681da177e4SLinus Torvalds if (lock->fl_end < 0) 70691da177e4SLinus Torvalds lock->fl_end = OFFSET_MAX; 70701da177e4SLinus Torvalds } 70711da177e4SLinus Torvalds 7072cae80b30SJeff Layton static fl_owner_t 707335aff067SChuck Lever nfsd4_lm_get_owner(fl_owner_t owner) 7074aef9583bSKinglong Mee { 7075cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 7076cae80b30SJeff Layton 7077cae80b30SJeff Layton nfs4_get_stateowner(&lo->lo_owner); 7078cae80b30SJeff Layton return owner; 7079aef9583bSKinglong Mee } 7080aef9583bSKinglong Mee 7081cae80b30SJeff Layton static void 708235aff067SChuck Lever nfsd4_lm_put_owner(fl_owner_t owner) 7083aef9583bSKinglong Mee { 7084cae80b30SJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; 7085aef9583bSKinglong Mee 7086cae80b30SJeff Layton if (lo) 7087aef9583bSKinglong Mee nfs4_put_stateowner(&lo->lo_owner); 7088aef9583bSKinglong Mee } 7089aef9583bSKinglong Mee 709027431affSDai Ngo /* return pointer to struct nfs4_client if client is expirable */ 709127431affSDai Ngo static bool 709227431affSDai Ngo nfsd4_lm_lock_expirable(struct file_lock *cfl) 709327431affSDai Ngo { 709427431affSDai Ngo struct nfs4_lockowner *lo = (struct nfs4_lockowner *)cfl->fl_owner; 709527431affSDai Ngo struct nfs4_client *clp = lo->lo_owner.so_client; 709627431affSDai Ngo struct nfsd_net *nn; 709727431affSDai Ngo 709827431affSDai Ngo if (try_to_expire_client(clp)) { 709927431affSDai Ngo nn = net_generic(clp->net, nfsd_net_id); 710027431affSDai Ngo mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); 710127431affSDai Ngo return true; 710227431affSDai Ngo } 710327431affSDai Ngo return false; 710427431affSDai Ngo } 710527431affSDai Ngo 710627431affSDai Ngo /* schedule laundromat to run immediately and wait for it to complete */ 710727431affSDai Ngo static void 710827431affSDai Ngo nfsd4_lm_expire_lock(void) 710927431affSDai Ngo { 711027431affSDai Ngo flush_workqueue(laundry_wq); 711127431affSDai Ngo } 711227431affSDai Ngo 711376d348faSJeff Layton static void 711476d348faSJeff Layton nfsd4_lm_notify(struct file_lock *fl) 711576d348faSJeff Layton { 711676d348faSJeff Layton struct nfs4_lockowner *lo = (struct nfs4_lockowner *)fl->fl_owner; 711776d348faSJeff Layton struct net *net = lo->lo_owner.so_client->net; 711876d348faSJeff Layton struct nfsd_net *nn = net_generic(net, nfsd_net_id); 711976d348faSJeff Layton struct nfsd4_blocked_lock *nbl = container_of(fl, 712076d348faSJeff Layton struct nfsd4_blocked_lock, nbl_lock); 712176d348faSJeff Layton bool queue = false; 712276d348faSJeff Layton 71237919d0a2SJeff Layton /* An empty list means that something else is going to be using it */ 71240cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 712576d348faSJeff Layton if (!list_empty(&nbl->nbl_list)) { 712676d348faSJeff Layton list_del_init(&nbl->nbl_list); 71277919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 712876d348faSJeff Layton queue = true; 712976d348faSJeff Layton } 71300cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 713176d348faSJeff Layton 71322cde7f81SChuck Lever if (queue) { 71332cde7f81SChuck Lever trace_nfsd_cb_notify_lock(lo, nbl); 713476d348faSJeff Layton nfsd4_run_cb(&nbl->nbl_cb); 713576d348faSJeff Layton } 71362cde7f81SChuck Lever } 713776d348faSJeff Layton 71387b021967SAlexey Dobriyan static const struct lock_manager_operations nfsd_posix_mng_ops = { 713927431affSDai Ngo .lm_mod_owner = THIS_MODULE, 714076d348faSJeff Layton .lm_notify = nfsd4_lm_notify, 714135aff067SChuck Lever .lm_get_owner = nfsd4_lm_get_owner, 714235aff067SChuck Lever .lm_put_owner = nfsd4_lm_put_owner, 714327431affSDai Ngo .lm_lock_expirable = nfsd4_lm_lock_expirable, 714427431affSDai Ngo .lm_expire_lock = nfsd4_lm_expire_lock, 7145d5b9026aSNeilBrown }; 71461da177e4SLinus Torvalds 71471da177e4SLinus Torvalds static inline void 71481da177e4SLinus Torvalds nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) 71491da177e4SLinus Torvalds { 7150fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lo; 71511da177e4SLinus Torvalds 7152d5b9026aSNeilBrown if (fl->fl_lmops == &nfsd_posix_mng_ops) { 7153fe0750e5SJ. Bruce Fields lo = (struct nfs4_lockowner *) fl->fl_owner; 71546f4859b8SJ. Bruce Fields xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner, 71556f4859b8SJ. Bruce Fields GFP_KERNEL); 71567c13f344SJ. Bruce Fields if (!deny->ld_owner.data) 71577c13f344SJ. Bruce Fields /* We just don't care that much */ 71587c13f344SJ. Bruce Fields goto nevermind; 7159fe0750e5SJ. Bruce Fields deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; 7160d5b9026aSNeilBrown } else { 71617c13f344SJ. Bruce Fields nevermind: 71627c13f344SJ. Bruce Fields deny->ld_owner.len = 0; 71637c13f344SJ. Bruce Fields deny->ld_owner.data = NULL; 7164d5b9026aSNeilBrown deny->ld_clientid.cl_boot = 0; 7165d5b9026aSNeilBrown deny->ld_clientid.cl_id = 0; 71661da177e4SLinus Torvalds } 71671da177e4SLinus Torvalds deny->ld_start = fl->fl_start; 716887df4de8SBenny Halevy deny->ld_length = NFS4_MAX_UINT64; 716987df4de8SBenny Halevy if (fl->fl_end != NFS4_MAX_UINT64) 71701da177e4SLinus Torvalds deny->ld_length = fl->fl_end - fl->fl_start + 1; 71711da177e4SLinus Torvalds deny->ld_type = NFS4_READ_LT; 71721da177e4SLinus Torvalds if (fl->fl_type != F_RDLCK) 71731da177e4SLinus Torvalds deny->ld_type = NFS4_WRITE_LT; 71741da177e4SLinus Torvalds } 71751da177e4SLinus Torvalds 7176fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 7177c8623999SKinglong Mee find_lockowner_str_locked(struct nfs4_client *clp, struct xdr_netobj *owner) 71781da177e4SLinus Torvalds { 7179d4f0489fSTrond Myklebust unsigned int strhashval = ownerstr_hashval(owner); 7180b3c32bcdSTrond Myklebust struct nfs4_stateowner *so; 71811da177e4SLinus Torvalds 71820a880a28STrond Myklebust lockdep_assert_held(&clp->cl_lock); 71830a880a28STrond Myklebust 7184d4f0489fSTrond Myklebust list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[strhashval], 7185d4f0489fSTrond Myklebust so_strhash) { 7186b3c32bcdSTrond Myklebust if (so->so_is_open_owner) 7187b3c32bcdSTrond Myklebust continue; 7188b5971afaSKinglong Mee if (same_owner_str(so, owner)) 7189b5971afaSKinglong Mee return lockowner(nfs4_get_stateowner(so)); 71901da177e4SLinus Torvalds } 71911da177e4SLinus Torvalds return NULL; 71921da177e4SLinus Torvalds } 71931da177e4SLinus Torvalds 7194c58c6610STrond Myklebust static struct nfs4_lockowner * 7195c8623999SKinglong Mee find_lockowner_str(struct nfs4_client *clp, struct xdr_netobj *owner) 7196c58c6610STrond Myklebust { 7197c58c6610STrond Myklebust struct nfs4_lockowner *lo; 7198c58c6610STrond Myklebust 7199d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7200c8623999SKinglong Mee lo = find_lockowner_str_locked(clp, owner); 7201d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 7202c58c6610STrond Myklebust return lo; 7203c58c6610STrond Myklebust } 7204c58c6610STrond Myklebust 72058f4b54c5SJeff Layton static void nfs4_unhash_lockowner(struct nfs4_stateowner *sop) 72068f4b54c5SJeff Layton { 7207c58c6610STrond Myklebust unhash_lockowner_locked(lockowner(sop)); 72088f4b54c5SJeff Layton } 72098f4b54c5SJeff Layton 72106b180f0bSJeff Layton static void nfs4_free_lockowner(struct nfs4_stateowner *sop) 72116b180f0bSJeff Layton { 72126b180f0bSJeff Layton struct nfs4_lockowner *lo = lockowner(sop); 72136b180f0bSJeff Layton 72146b180f0bSJeff Layton kmem_cache_free(lockowner_slab, lo); 72156b180f0bSJeff Layton } 72166b180f0bSJeff Layton 72176b180f0bSJeff Layton static const struct nfs4_stateowner_operations lockowner_ops = { 72188f4b54c5SJeff Layton .so_unhash = nfs4_unhash_lockowner, 72196b180f0bSJeff Layton .so_free = nfs4_free_lockowner, 72206b180f0bSJeff Layton }; 72216b180f0bSJeff Layton 72221da177e4SLinus Torvalds /* 72231da177e4SLinus Torvalds * Alloc a lock owner structure. 72241da177e4SLinus Torvalds * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 722525985edcSLucas De Marchi * occurred. 72261da177e4SLinus Torvalds * 722716bfdaafSJ. Bruce Fields * strhashval = ownerstr_hashval 72281da177e4SLinus Torvalds */ 7229fe0750e5SJ. Bruce Fields static struct nfs4_lockowner * 7230c58c6610STrond Myklebust alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, 7231c58c6610STrond Myklebust struct nfs4_ol_stateid *open_stp, 7232c58c6610STrond Myklebust struct nfsd4_lock *lock) 7233c58c6610STrond Myklebust { 7234c58c6610STrond Myklebust struct nfs4_lockowner *lo, *ret; 72351da177e4SLinus Torvalds 7236fe0750e5SJ. Bruce Fields lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); 7237fe0750e5SJ. Bruce Fields if (!lo) 72381da177e4SLinus Torvalds return NULL; 723976d348faSJeff Layton INIT_LIST_HEAD(&lo->lo_blocked); 7240fe0750e5SJ. Bruce Fields INIT_LIST_HEAD(&lo->lo_owner.so_stateids); 7241fe0750e5SJ. Bruce Fields lo->lo_owner.so_is_open_owner = 0; 72425db1c03fSJeff Layton lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; 72436b180f0bSJeff Layton lo->lo_owner.so_ops = &lockowner_ops; 7244d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7245c8623999SKinglong Mee ret = find_lockowner_str_locked(clp, &lock->lk_new_owner); 7246c58c6610STrond Myklebust if (ret == NULL) { 7247c58c6610STrond Myklebust list_add(&lo->lo_owner.so_strhash, 7248d4f0489fSTrond Myklebust &clp->cl_ownerstr_hashtbl[strhashval]); 7249c58c6610STrond Myklebust ret = lo; 7250c58c6610STrond Myklebust } else 7251d50ffdedSKinglong Mee nfs4_free_stateowner(&lo->lo_owner); 7252d50ffdedSKinglong Mee 7253d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 7254340f0ba1SJ. Bruce Fields return ret; 72551da177e4SLinus Torvalds } 72561da177e4SLinus Torvalds 7257fd1fd685STrond Myklebust static struct nfs4_ol_stateid * 7258a451b123STrond Myklebust find_lock_stateid(const struct nfs4_lockowner *lo, 7259a451b123STrond Myklebust const struct nfs4_ol_stateid *ost) 7260fd1fd685STrond Myklebust { 7261fd1fd685STrond Myklebust struct nfs4_ol_stateid *lst; 7262fd1fd685STrond Myklebust 7263a451b123STrond Myklebust lockdep_assert_held(&ost->st_stid.sc_client->cl_lock); 7264fd1fd685STrond Myklebust 7265a451b123STrond Myklebust /* If ost is not hashed, ost->st_locks will not be valid */ 7266a451b123STrond Myklebust if (!nfs4_ol_stateid_unhashed(ost)) 7267a451b123STrond Myklebust list_for_each_entry(lst, &ost->st_locks, st_locks) { 7268a451b123STrond Myklebust if (lst->st_stateowner == &lo->lo_owner) { 7269fd1fd685STrond Myklebust refcount_inc(&lst->st_stid.sc_count); 7270fd1fd685STrond Myklebust return lst; 7271fd1fd685STrond Myklebust } 7272fd1fd685STrond Myklebust } 7273fd1fd685STrond Myklebust return NULL; 7274fd1fd685STrond Myklebust } 7275fd1fd685STrond Myklebust 7276beeca19cSTrond Myklebust static struct nfs4_ol_stateid * 7277356a95ecSJeff Layton init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo, 7278356a95ecSJeff Layton struct nfs4_file *fp, struct inode *inode, 7279f9c00c3aSJeff Layton struct nfs4_ol_stateid *open_stp) 72801da177e4SLinus Torvalds { 7281d3b313a4SJ. Bruce Fields struct nfs4_client *clp = lo->lo_owner.so_client; 7282beeca19cSTrond Myklebust struct nfs4_ol_stateid *retstp; 72831da177e4SLinus Torvalds 7284beeca19cSTrond Myklebust mutex_init(&stp->st_mutex); 72854f34bd05SAndrew Elble mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX); 7286beeca19cSTrond Myklebust retry: 7287beeca19cSTrond Myklebust spin_lock(&clp->cl_lock); 7288a451b123STrond Myklebust if (nfs4_ol_stateid_unhashed(open_stp)) 7289a451b123STrond Myklebust goto out_close; 7290a451b123STrond Myklebust retstp = find_lock_stateid(lo, open_stp); 7291beeca19cSTrond Myklebust if (retstp) 7292a451b123STrond Myklebust goto out_found; 7293a15dfcd5SElena Reshetova refcount_inc(&stp->st_stid.sc_count); 72943abdb607SJ. Bruce Fields stp->st_stid.sc_type = NFS4_LOCK_STID; 7295b5971afaSKinglong Mee stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner); 729613cd2184SNeilBrown get_nfs4_file(fp); 729711b9164aSTrond Myklebust stp->st_stid.sc_file = fp; 72980997b173SJ. Bruce Fields stp->st_access_bmap = 0; 72991da177e4SLinus Torvalds stp->st_deny_bmap = open_stp->st_deny_bmap; 73004c4cd222SNeilBrown stp->st_openstp = open_stp; 7301a451b123STrond Myklebust spin_lock(&fp->fi_lock); 73023c87b9b7STrond Myklebust list_add(&stp->st_locks, &open_stp->st_locks); 73031c755dc1SJeff Layton list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 73041d31a253STrond Myklebust list_add(&stp->st_perfile, &fp->fi_stateids); 73051d31a253STrond Myklebust spin_unlock(&fp->fi_lock); 7306beeca19cSTrond Myklebust spin_unlock(&clp->cl_lock); 7307a451b123STrond Myklebust return stp; 7308a451b123STrond Myklebust out_found: 7309a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 7310beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) { 7311beeca19cSTrond Myklebust nfs4_put_stid(&retstp->st_stid); 7312beeca19cSTrond Myklebust goto retry; 7313beeca19cSTrond Myklebust } 7314beeca19cSTrond Myklebust /* To keep mutex tracking happy */ 7315beeca19cSTrond Myklebust mutex_unlock(&stp->st_mutex); 7316a451b123STrond Myklebust return retstp; 7317a451b123STrond Myklebust out_close: 7318a451b123STrond Myklebust spin_unlock(&clp->cl_lock); 7319a451b123STrond Myklebust mutex_unlock(&stp->st_mutex); 7320a451b123STrond Myklebust return NULL; 73211da177e4SLinus Torvalds } 73221da177e4SLinus Torvalds 7323c53530daSJeff Layton static struct nfs4_ol_stateid * 7324356a95ecSJeff Layton find_or_create_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fi, 7325356a95ecSJeff Layton struct inode *inode, struct nfs4_ol_stateid *ost, 7326356a95ecSJeff Layton bool *new) 7327356a95ecSJeff Layton { 7328356a95ecSJeff Layton struct nfs4_stid *ns = NULL; 7329356a95ecSJeff Layton struct nfs4_ol_stateid *lst; 7330356a95ecSJeff Layton struct nfs4_openowner *oo = openowner(ost->st_stateowner); 7331356a95ecSJeff Layton struct nfs4_client *clp = oo->oo_owner.so_client; 7332356a95ecSJeff Layton 7333beeca19cSTrond Myklebust *new = false; 7334356a95ecSJeff Layton spin_lock(&clp->cl_lock); 7335a451b123STrond Myklebust lst = find_lock_stateid(lo, ost); 7336356a95ecSJeff Layton spin_unlock(&clp->cl_lock); 7337beeca19cSTrond Myklebust if (lst != NULL) { 7338beeca19cSTrond Myklebust if (nfsd4_lock_ol_stateid(lst) == nfs_ok) 7339beeca19cSTrond Myklebust goto out; 7340beeca19cSTrond Myklebust nfs4_put_stid(&lst->st_stid); 7341beeca19cSTrond Myklebust } 7342d19fb70dSKinglong Mee ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid); 7343356a95ecSJeff Layton if (ns == NULL) 7344356a95ecSJeff Layton return NULL; 7345356a95ecSJeff Layton 7346beeca19cSTrond Myklebust lst = init_lock_stateid(openlockstateid(ns), lo, fi, inode, ost); 7347beeca19cSTrond Myklebust if (lst == openlockstateid(ns)) 7348356a95ecSJeff Layton *new = true; 7349beeca19cSTrond Myklebust else 7350356a95ecSJeff Layton nfs4_put_stid(ns); 7351beeca19cSTrond Myklebust out: 7352356a95ecSJeff Layton return lst; 7353356a95ecSJeff Layton } 7354c53530daSJeff Layton 7355fd39ca9aSNeilBrown static int 73561da177e4SLinus Torvalds check_lock_length(u64 offset, u64 length) 73571da177e4SLinus Torvalds { 735887df4de8SBenny Halevy return ((length == 0) || ((length != NFS4_MAX_UINT64) && 7359e7969315SKinglong Mee (length > ~offset))); 73601da177e4SLinus Torvalds } 73611da177e4SLinus Torvalds 7362dcef0413SJ. Bruce Fields static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) 73630997b173SJ. Bruce Fields { 736411b9164aSTrond Myklebust struct nfs4_file *fp = lock_stp->st_stid.sc_file; 73650997b173SJ. Bruce Fields 73667214e860SJeff Layton lockdep_assert_held(&fp->fi_lock); 73677214e860SJeff Layton 736882c5ff1bSJeff Layton if (test_access(access, lock_stp)) 73690997b173SJ. Bruce Fields return; 737012659651SJeff Layton __nfs4_file_get_access(fp, access); 737182c5ff1bSJeff Layton set_access(access, lock_stp); 73720997b173SJ. Bruce Fields } 73730997b173SJ. Bruce Fields 7374356a95ecSJeff Layton static __be32 7375356a95ecSJeff Layton lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 7376356a95ecSJeff Layton struct nfs4_ol_stateid *ost, 7377356a95ecSJeff Layton struct nfsd4_lock *lock, 7378dd257933SJeff Layton struct nfs4_ol_stateid **plst, bool *new) 737964a284d0SJ. Bruce Fields { 73805db1c03fSJeff Layton __be32 status; 738111b9164aSTrond Myklebust struct nfs4_file *fi = ost->st_stid.sc_file; 738264a284d0SJ. Bruce Fields struct nfs4_openowner *oo = openowner(ost->st_stateowner); 738364a284d0SJ. Bruce Fields struct nfs4_client *cl = oo->oo_owner.so_client; 73842b0143b5SDavid Howells struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 738564a284d0SJ. Bruce Fields struct nfs4_lockowner *lo; 7386dd257933SJeff Layton struct nfs4_ol_stateid *lst; 738764a284d0SJ. Bruce Fields unsigned int strhashval; 738864a284d0SJ. Bruce Fields 7389c8623999SKinglong Mee lo = find_lockowner_str(cl, &lock->lk_new_owner); 7390c53530daSJeff Layton if (!lo) { 739176f6c9e1SKinglong Mee strhashval = ownerstr_hashval(&lock->lk_new_owner); 739264a284d0SJ. Bruce Fields lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); 739364a284d0SJ. Bruce Fields if (lo == NULL) 739464a284d0SJ. Bruce Fields return nfserr_jukebox; 7395c53530daSJeff Layton } else { 7396c53530daSJeff Layton /* with an existing lockowner, seqids must be the same */ 73975db1c03fSJeff Layton status = nfserr_bad_seqid; 7398c53530daSJeff Layton if (!cstate->minorversion && 7399c53530daSJeff Layton lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) 74005db1c03fSJeff Layton goto out; 7401c53530daSJeff Layton } 7402c53530daSJeff Layton 7403dd257933SJeff Layton lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 7404dd257933SJeff Layton if (lst == NULL) { 74055db1c03fSJeff Layton status = nfserr_jukebox; 74065db1c03fSJeff Layton goto out; 740764a284d0SJ. Bruce Fields } 7408dd257933SJeff Layton 74095db1c03fSJeff Layton status = nfs_ok; 7410dd257933SJeff Layton *plst = lst; 74115db1c03fSJeff Layton out: 74125db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 74135db1c03fSJeff Layton return status; 741464a284d0SJ. Bruce Fields } 741564a284d0SJ. Bruce Fields 74161da177e4SLinus Torvalds /* 74171da177e4SLinus Torvalds * LOCK operation 74181da177e4SLinus Torvalds */ 7419b37ad28bSAl Viro __be32 7420ca364317SJ.Bruce Fields nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7421eb69853dSChristoph Hellwig union nfsd4_op_u *u) 74221da177e4SLinus Torvalds { 7423eb69853dSChristoph Hellwig struct nfsd4_lock *lock = &u->lock; 7424fe0750e5SJ. Bruce Fields struct nfs4_openowner *open_sop = NULL; 7425fe0750e5SJ. Bruce Fields struct nfs4_lockowner *lock_sop = NULL; 74263d0fabd5STrond Myklebust struct nfs4_ol_stateid *lock_stp = NULL; 74270667b1e9STrond Myklebust struct nfs4_ol_stateid *open_stp = NULL; 74287214e860SJeff Layton struct nfs4_file *fp; 7429eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 743076d348faSJeff Layton struct nfsd4_blocked_lock *nbl = NULL; 743121179d81SJeff Layton struct file_lock *file_lock = NULL; 743221179d81SJeff Layton struct file_lock *conflock = NULL; 7433b37ad28bSAl Viro __be32 status = 0; 7434b34f27aaSJ. Bruce Fields int lkflg; 7435b8dd7b9aSAl Viro int err; 74365db1c03fSJeff Layton bool new = false; 743776d348faSJeff Layton unsigned char fl_type; 743876d348faSJeff Layton unsigned int fl_flags = FL_POSIX; 74393320fef1SStanislav Kinsbursky struct net *net = SVC_NET(rqstp); 74403320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 74411da177e4SLinus Torvalds 74421da177e4SLinus Torvalds dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", 74431da177e4SLinus Torvalds (long long) lock->lk_offset, 74441da177e4SLinus Torvalds (long long) lock->lk_length); 74451da177e4SLinus Torvalds 74461da177e4SLinus Torvalds if (check_lock_length(lock->lk_offset, lock->lk_length)) 74471da177e4SLinus Torvalds return nfserr_inval; 74481da177e4SLinus Torvalds 7449ca364317SJ.Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, 74508837abcaSMiklos Szeredi S_IFREG, NFSD_MAY_LOCK))) { 7451a6f6ef2fSAndy Adamson dprintk("NFSD: nfsd4_lock: permission denied!\n"); 7452a6f6ef2fSAndy Adamson return status; 7453a6f6ef2fSAndy Adamson } 7454a6f6ef2fSAndy Adamson 74551da177e4SLinus Torvalds if (lock->lk_is_new) { 7456684e5638SJ. Bruce Fields if (nfsd4_has_session(cstate)) 7457684e5638SJ. Bruce Fields /* See rfc 5661 18.10.3: given clientid is ignored: */ 745876f6c9e1SKinglong Mee memcpy(&lock->lk_new_clientid, 7459ec59659bSJ. Bruce Fields &cstate->clp->cl_clientid, 7460684e5638SJ. Bruce Fields sizeof(clientid_t)); 7461684e5638SJ. Bruce Fields 74621da177e4SLinus Torvalds /* validate and update open stateid and open seqid */ 7463c0a5d93eSJ. Bruce Fields status = nfs4_preprocess_confirmed_seqid_op(cstate, 74641da177e4SLinus Torvalds lock->lk_new_open_seqid, 74651da177e4SLinus Torvalds &lock->lk_new_open_stateid, 74663320fef1SStanislav Kinsbursky &open_stp, nn); 746737515177SNeilBrown if (status) 74681da177e4SLinus Torvalds goto out; 7469feb9dad5SOleg Drokin mutex_unlock(&open_stp->st_mutex); 7470fe0750e5SJ. Bruce Fields open_sop = openowner(open_stp->st_stateowner); 7471b34f27aaSJ. Bruce Fields status = nfserr_bad_stateid; 7472684e5638SJ. Bruce Fields if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 747376f6c9e1SKinglong Mee &lock->lk_new_clientid)) 7474b34f27aaSJ. Bruce Fields goto out; 747564a284d0SJ. Bruce Fields status = lookup_or_create_lock_state(cstate, open_stp, lock, 74765db1c03fSJeff Layton &lock_stp, &new); 74773d0fabd5STrond Myklebust } else { 7478dd453dfdSBenny Halevy status = nfs4_preprocess_seqid_op(cstate, 74791da177e4SLinus Torvalds lock->lk_old_lock_seqid, 74801da177e4SLinus Torvalds &lock->lk_old_lock_stateid, 74813320fef1SStanislav Kinsbursky NFS4_LOCK_STID, &lock_stp, nn); 74823d0fabd5STrond Myklebust } 74831da177e4SLinus Torvalds if (status) 74841da177e4SLinus Torvalds goto out; 7485fe0750e5SJ. Bruce Fields lock_sop = lockowner(lock_stp->st_stateowner); 74861da177e4SLinus Torvalds 7487b34f27aaSJ. Bruce Fields lkflg = setlkflg(lock->lk_type); 7488b34f27aaSJ. Bruce Fields status = nfs4_check_openmode(lock_stp, lkflg); 7489b34f27aaSJ. Bruce Fields if (status) 7490b34f27aaSJ. Bruce Fields goto out; 7491b34f27aaSJ. Bruce Fields 74920dd395dcSNeilBrown status = nfserr_grace; 74933320fef1SStanislav Kinsbursky if (locks_in_grace(net) && !lock->lk_reclaim) 74940dd395dcSNeilBrown goto out; 74950dd395dcSNeilBrown status = nfserr_no_grace; 74963320fef1SStanislav Kinsbursky if (!locks_in_grace(net) && lock->lk_reclaim) 74970dd395dcSNeilBrown goto out; 74980dd395dcSNeilBrown 7499bb0a55bbSJ. Bruce Fields if (lock->lk_reclaim) 7500bb0a55bbSJ. Bruce Fields fl_flags |= FL_RECLAIM; 7501bb0a55bbSJ. Bruce Fields 750211b9164aSTrond Myklebust fp = lock_stp->st_stid.sc_file; 75031da177e4SLinus Torvalds switch (lock->lk_type) { 75041da177e4SLinus Torvalds case NFS4_READW_LT: 750540595cdcSJ. Bruce Fields if (nfsd4_has_session(cstate)) 750676d348faSJeff Layton fl_flags |= FL_SLEEP; 7507df561f66SGustavo A. R. Silva fallthrough; 750876d348faSJeff Layton case NFS4_READ_LT: 75097214e860SJeff Layton spin_lock(&fp->fi_lock); 7510eb82dd39SJeff Layton nf = find_readable_file_locked(fp); 7511eb82dd39SJeff Layton if (nf) 75120997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); 75137214e860SJeff Layton spin_unlock(&fp->fi_lock); 751476d348faSJeff Layton fl_type = F_RDLCK; 75151da177e4SLinus Torvalds break; 75161da177e4SLinus Torvalds case NFS4_WRITEW_LT: 751740595cdcSJ. Bruce Fields if (nfsd4_has_session(cstate)) 751876d348faSJeff Layton fl_flags |= FL_SLEEP; 7519df561f66SGustavo A. R. Silva fallthrough; 752076d348faSJeff Layton case NFS4_WRITE_LT: 75217214e860SJeff Layton spin_lock(&fp->fi_lock); 7522eb82dd39SJeff Layton nf = find_writeable_file_locked(fp); 7523eb82dd39SJeff Layton if (nf) 75240997b173SJ. Bruce Fields get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); 75257214e860SJeff Layton spin_unlock(&fp->fi_lock); 752676d348faSJeff Layton fl_type = F_WRLCK; 75271da177e4SLinus Torvalds break; 75281da177e4SLinus Torvalds default: 75291da177e4SLinus Torvalds status = nfserr_inval; 75301da177e4SLinus Torvalds goto out; 75311da177e4SLinus Torvalds } 753276d348faSJeff Layton 7533eb82dd39SJeff Layton if (!nf) { 7534f9d7562fSJ. Bruce Fields status = nfserr_openmode; 7535f9d7562fSJ. Bruce Fields goto out; 7536f9d7562fSJ. Bruce Fields } 7537aef9583bSKinglong Mee 753840595cdcSJ. Bruce Fields /* 753940595cdcSJ. Bruce Fields * Most filesystems with their own ->lock operations will block 754040595cdcSJ. Bruce Fields * the nfsd thread waiting to acquire the lock. That leads to 754140595cdcSJ. Bruce Fields * deadlocks (we don't want every nfsd thread tied up waiting 754240595cdcSJ. Bruce Fields * for file locks), so don't attempt blocking lock notifications 754340595cdcSJ. Bruce Fields * on those filesystems: 754440595cdcSJ. Bruce Fields */ 754540595cdcSJ. Bruce Fields if (nf->nf_file->f_op->lock) 754640595cdcSJ. Bruce Fields fl_flags &= ~FL_SLEEP; 754740595cdcSJ. Bruce Fields 754876d348faSJeff Layton nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); 754976d348faSJeff Layton if (!nbl) { 755076d348faSJeff Layton dprintk("NFSD: %s: unable to allocate block!\n", __func__); 755176d348faSJeff Layton status = nfserr_jukebox; 755276d348faSJeff Layton goto out; 755376d348faSJeff Layton } 755476d348faSJeff Layton 755576d348faSJeff Layton file_lock = &nbl->nbl_lock; 755676d348faSJeff Layton file_lock->fl_type = fl_type; 7557aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner)); 755821179d81SJeff Layton file_lock->fl_pid = current->tgid; 7559eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 756076d348faSJeff Layton file_lock->fl_flags = fl_flags; 756121179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 756221179d81SJeff Layton file_lock->fl_start = lock->lk_offset; 756321179d81SJeff Layton file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); 756421179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 75651da177e4SLinus Torvalds 756621179d81SJeff Layton conflock = locks_alloc_lock(); 756721179d81SJeff Layton if (!conflock) { 756821179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 756921179d81SJeff Layton status = nfserr_jukebox; 757021179d81SJeff Layton goto out; 757121179d81SJeff Layton } 75721da177e4SLinus Torvalds 757376d348faSJeff Layton if (fl_flags & FL_SLEEP) { 757420b7d86fSArnd Bergmann nbl->nbl_time = ktime_get_boottime_seconds(); 75750cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 757676d348faSJeff Layton list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); 75777919d0a2SJeff Layton list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); 757847446d74SVasily Averin kref_get(&nbl->nbl_kref); 75790cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 758076d348faSJeff Layton } 758176d348faSJeff Layton 7582eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, conflock); 758376d348faSJeff Layton switch (err) { 75841da177e4SLinus Torvalds case 0: /* success! */ 75859767feb2SJeff Layton nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid); 7586b8dd7b9aSAl Viro status = 0; 758703f318caSJ. Bruce Fields if (lock->lk_reclaim) 758803f318caSJ. Bruce Fields nn->somebody_reclaimed = true; 7589eb76b3fdSAndy Adamson break; 759076d348faSJeff Layton case FILE_LOCK_DEFERRED: 759147446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 759276d348faSJeff Layton nbl = NULL; 7593df561f66SGustavo A. R. Silva fallthrough; 759476d348faSJeff Layton case -EAGAIN: /* conflock holds conflicting lock */ 7595eb76b3fdSAndy Adamson status = nfserr_denied; 7596eb76b3fdSAndy Adamson dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); 759721179d81SJeff Layton nfs4_set_lock_denied(conflock, &lock->lk_denied); 7598eb76b3fdSAndy Adamson break; 759976d348faSJeff Layton case -EDEADLK: 76001da177e4SLinus Torvalds status = nfserr_deadlock; 7601eb76b3fdSAndy Adamson break; 76021da177e4SLinus Torvalds default: 7603fd85b817SMarc Eshel dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); 76043e772463SJ. Bruce Fields status = nfserrno(err); 7605eb76b3fdSAndy Adamson break; 76061da177e4SLinus Torvalds } 76071da177e4SLinus Torvalds out: 760876d348faSJeff Layton if (nbl) { 760976d348faSJeff Layton /* dequeue it if we queued it before */ 761076d348faSJeff Layton if (fl_flags & FL_SLEEP) { 76110cc11a61SJeff Layton spin_lock(&nn->blocked_locks_lock); 761247446d74SVasily Averin if (!list_empty(&nbl->nbl_list) && 761347446d74SVasily Averin !list_empty(&nbl->nbl_lru)) { 761476d348faSJeff Layton list_del_init(&nbl->nbl_list); 76157919d0a2SJeff Layton list_del_init(&nbl->nbl_lru); 761647446d74SVasily Averin kref_put(&nbl->nbl_kref, free_nbl); 761747446d74SVasily Averin } 761847446d74SVasily Averin /* nbl can use one of lists to be linked to reaplist */ 76190cc11a61SJeff Layton spin_unlock(&nn->blocked_locks_lock); 762076d348faSJeff Layton } 762176d348faSJeff Layton free_blocked_lock(nbl); 762276d348faSJeff Layton } 7623eb82dd39SJeff Layton if (nf) 7624eb82dd39SJeff Layton nfsd_file_put(nf); 76255db1c03fSJeff Layton if (lock_stp) { 76265db1c03fSJeff Layton /* Bump seqid manually if the 4.0 replay owner is openowner */ 76275db1c03fSJeff Layton if (cstate->replay_owner && 76285db1c03fSJeff Layton cstate->replay_owner != &lock_sop->lo_owner && 76295db1c03fSJeff Layton seqid_mutating_err(ntohl(status))) 76305db1c03fSJeff Layton lock_sop->lo_owner.so_seqid++; 76315db1c03fSJeff Layton 76325db1c03fSJeff Layton /* 76335db1c03fSJeff Layton * If this is a new, never-before-used stateid, and we are 76345db1c03fSJeff Layton * returning an error, then just go ahead and release it. 76355db1c03fSJeff Layton */ 763625020720SJ. Bruce Fields if (status && new) 76375db1c03fSJeff Layton release_lock_stateid(lock_stp); 7638beeca19cSTrond Myklebust 7639beeca19cSTrond Myklebust mutex_unlock(&lock_stp->st_mutex); 76405db1c03fSJeff Layton 76413d0fabd5STrond Myklebust nfs4_put_stid(&lock_stp->st_stid); 76425db1c03fSJeff Layton } 76430667b1e9STrond Myklebust if (open_stp) 76440667b1e9STrond Myklebust nfs4_put_stid(&open_stp->st_stid); 76459411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 764621179d81SJeff Layton if (conflock) 764721179d81SJeff Layton locks_free_lock(conflock); 76481da177e4SLinus Torvalds return status; 76491da177e4SLinus Torvalds } 76501da177e4SLinus Torvalds 76511da177e4SLinus Torvalds /* 765255ef1274SJ. Bruce Fields * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN, 765355ef1274SJ. Bruce Fields * so we do a temporary open here just to get an open file to pass to 76540bcc7ca4SJ. Bruce Fields * vfs_test_lock. 765555ef1274SJ. Bruce Fields */ 765604da6e9dSAl Viro static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) 765755ef1274SJ. Bruce Fields { 76586b556ca2SJeff Layton struct nfsd_file *nf; 7659bb4d53d6SNeilBrown struct inode *inode; 7660217fd6f6SJ. Bruce Fields __be32 err; 7661217fd6f6SJ. Bruce Fields 7662217fd6f6SJ. Bruce Fields err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); 7663217fd6f6SJ. Bruce Fields if (err) 7664217fd6f6SJ. Bruce Fields return err; 7665bb4d53d6SNeilBrown inode = fhp->fh_dentry->d_inode; 7666bb4d53d6SNeilBrown inode_lock(inode); /* to block new leases till after test_lock: */ 7667bb4d53d6SNeilBrown err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); 7668217fd6f6SJ. Bruce Fields if (err) 7669217fd6f6SJ. Bruce Fields goto out; 76700bcc7ca4SJ. Bruce Fields lock->fl_file = nf->nf_file; 76716b556ca2SJeff Layton err = nfserrno(vfs_test_lock(nf->nf_file, lock)); 76720bcc7ca4SJ. Bruce Fields lock->fl_file = NULL; 7673217fd6f6SJ. Bruce Fields out: 7674bb4d53d6SNeilBrown inode_unlock(inode); 76756b556ca2SJeff Layton nfsd_file_put(nf); 767655ef1274SJ. Bruce Fields return err; 767755ef1274SJ. Bruce Fields } 767855ef1274SJ. Bruce Fields 767955ef1274SJ. Bruce Fields /* 76801da177e4SLinus Torvalds * LOCKT operation 76811da177e4SLinus Torvalds */ 7682b37ad28bSAl Viro __be32 7683ca364317SJ.Bruce Fields nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7684eb69853dSChristoph Hellwig union nfsd4_op_u *u) 76851da177e4SLinus Torvalds { 7686eb69853dSChristoph Hellwig struct nfsd4_lockt *lockt = &u->lockt; 768721179d81SJeff Layton struct file_lock *file_lock = NULL; 76885db1c03fSJeff Layton struct nfs4_lockowner *lo = NULL; 7689b37ad28bSAl Viro __be32 status; 76907f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 76911da177e4SLinus Torvalds 76925ccb0066SStanislav Kinsbursky if (locks_in_grace(SVC_NET(rqstp))) 76931da177e4SLinus Torvalds return nfserr_grace; 76941da177e4SLinus Torvalds 76951da177e4SLinus Torvalds if (check_lock_length(lockt->lt_offset, lockt->lt_length)) 76961da177e4SLinus Torvalds return nfserr_inval; 76971da177e4SLinus Torvalds 76989b2ef62bSJ. Bruce Fields if (!nfsd4_has_session(cstate)) { 7699f71475baSJ. Bruce Fields status = set_client(&lockt->lt_clientid, cstate, nn); 77009b2ef62bSJ. Bruce Fields if (status) 77011da177e4SLinus Torvalds goto out; 77029b2ef62bSJ. Bruce Fields } 77031da177e4SLinus Torvalds 770475c096f7SJ. Bruce Fields if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) 77051da177e4SLinus Torvalds goto out; 77061da177e4SLinus Torvalds 770721179d81SJeff Layton file_lock = locks_alloc_lock(); 770821179d81SJeff Layton if (!file_lock) { 770921179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 771021179d81SJeff Layton status = nfserr_jukebox; 771121179d81SJeff Layton goto out; 771221179d81SJeff Layton } 77136cd90662SKinglong Mee 77141da177e4SLinus Torvalds switch (lockt->lt_type) { 77151da177e4SLinus Torvalds case NFS4_READ_LT: 77161da177e4SLinus Torvalds case NFS4_READW_LT: 771721179d81SJeff Layton file_lock->fl_type = F_RDLCK; 77181da177e4SLinus Torvalds break; 77191da177e4SLinus Torvalds case NFS4_WRITE_LT: 77201da177e4SLinus Torvalds case NFS4_WRITEW_LT: 772121179d81SJeff Layton file_lock->fl_type = F_WRLCK; 77221da177e4SLinus Torvalds break; 77231da177e4SLinus Torvalds default: 77242fdada03SJ. Bruce Fields dprintk("NFSD: nfs4_lockt: bad lock type!\n"); 77251da177e4SLinus Torvalds status = nfserr_inval; 77261da177e4SLinus Torvalds goto out; 77271da177e4SLinus Torvalds } 77281da177e4SLinus Torvalds 7729c8623999SKinglong Mee lo = find_lockowner_str(cstate->clp, &lockt->lt_owner); 7730fe0750e5SJ. Bruce Fields if (lo) 773121179d81SJeff Layton file_lock->fl_owner = (fl_owner_t)lo; 773221179d81SJeff Layton file_lock->fl_pid = current->tgid; 773321179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 77341da177e4SLinus Torvalds 773521179d81SJeff Layton file_lock->fl_start = lockt->lt_offset; 773621179d81SJeff Layton file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); 77371da177e4SLinus Torvalds 773821179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 77391da177e4SLinus Torvalds 774021179d81SJeff Layton status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); 774104da6e9dSAl Viro if (status) 7742fd85b817SMarc Eshel goto out; 774304da6e9dSAl Viro 774421179d81SJeff Layton if (file_lock->fl_type != F_UNLCK) { 77451da177e4SLinus Torvalds status = nfserr_denied; 774621179d81SJeff Layton nfs4_set_lock_denied(file_lock, &lockt->lt_denied); 77471da177e4SLinus Torvalds } 77481da177e4SLinus Torvalds out: 77495db1c03fSJeff Layton if (lo) 77505db1c03fSJeff Layton nfs4_put_stateowner(&lo->lo_owner); 775121179d81SJeff Layton if (file_lock) 775221179d81SJeff Layton locks_free_lock(file_lock); 77531da177e4SLinus Torvalds return status; 77541da177e4SLinus Torvalds } 77551da177e4SLinus Torvalds 7756b37ad28bSAl Viro __be32 7757ca364317SJ.Bruce Fields nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 7758eb69853dSChristoph Hellwig union nfsd4_op_u *u) 77591da177e4SLinus Torvalds { 7760eb69853dSChristoph Hellwig struct nfsd4_locku *locku = &u->locku; 7761dcef0413SJ. Bruce Fields struct nfs4_ol_stateid *stp; 7762eb82dd39SJeff Layton struct nfsd_file *nf = NULL; 776321179d81SJeff Layton struct file_lock *file_lock = NULL; 7764b37ad28bSAl Viro __be32 status; 7765b8dd7b9aSAl Viro int err; 77663320fef1SStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 77671da177e4SLinus Torvalds 77681da177e4SLinus Torvalds dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", 77691da177e4SLinus Torvalds (long long) locku->lu_offset, 77701da177e4SLinus Torvalds (long long) locku->lu_length); 77711da177e4SLinus Torvalds 77721da177e4SLinus Torvalds if (check_lock_length(locku->lu_offset, locku->lu_length)) 77731da177e4SLinus Torvalds return nfserr_inval; 77741da177e4SLinus Torvalds 77759072d5c6SJ. Bruce Fields status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, 77763320fef1SStanislav Kinsbursky &locku->lu_stateid, NFS4_LOCK_STID, 77773320fef1SStanislav Kinsbursky &stp, nn); 77789072d5c6SJ. Bruce Fields if (status) 77791da177e4SLinus Torvalds goto out; 7780eb82dd39SJeff Layton nf = find_any_file(stp->st_stid.sc_file); 7781eb82dd39SJeff Layton if (!nf) { 7782f9d7562fSJ. Bruce Fields status = nfserr_lock_range; 7783858cc573STrond Myklebust goto put_stateid; 7784f9d7562fSJ. Bruce Fields } 778521179d81SJeff Layton file_lock = locks_alloc_lock(); 778621179d81SJeff Layton if (!file_lock) { 778721179d81SJeff Layton dprintk("NFSD: %s: unable to allocate lock!\n", __func__); 778821179d81SJeff Layton status = nfserr_jukebox; 7789eb82dd39SJeff Layton goto put_file; 779021179d81SJeff Layton } 77916cd90662SKinglong Mee 779221179d81SJeff Layton file_lock->fl_type = F_UNLCK; 7793aef9583bSKinglong Mee file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner)); 779421179d81SJeff Layton file_lock->fl_pid = current->tgid; 7795eb82dd39SJeff Layton file_lock->fl_file = nf->nf_file; 779621179d81SJeff Layton file_lock->fl_flags = FL_POSIX; 779721179d81SJeff Layton file_lock->fl_lmops = &nfsd_posix_mng_ops; 779821179d81SJeff Layton file_lock->fl_start = locku->lu_offset; 77991da177e4SLinus Torvalds 780021179d81SJeff Layton file_lock->fl_end = last_byte_offset(locku->lu_offset, 780121179d81SJeff Layton locku->lu_length); 780221179d81SJeff Layton nfs4_transform_lock_offset(file_lock); 78031da177e4SLinus Torvalds 7804eb82dd39SJeff Layton err = vfs_lock_file(nf->nf_file, F_SETLK, file_lock, NULL); 7805b8dd7b9aSAl Viro if (err) { 7806fd85b817SMarc Eshel dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); 78071da177e4SLinus Torvalds goto out_nfserr; 78081da177e4SLinus Torvalds } 78099767feb2SJeff Layton nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid); 7810eb82dd39SJeff Layton put_file: 7811eb82dd39SJeff Layton nfsd_file_put(nf); 7812858cc573STrond Myklebust put_stateid: 7813feb9dad5SOleg Drokin mutex_unlock(&stp->st_mutex); 7814858cc573STrond Myklebust nfs4_put_stid(&stp->st_stid); 78151da177e4SLinus Torvalds out: 78169411b1d4SJ. Bruce Fields nfsd4_bump_seqid(cstate, status); 781721179d81SJeff Layton if (file_lock) 781821179d81SJeff Layton locks_free_lock(file_lock); 78191da177e4SLinus Torvalds return status; 78201da177e4SLinus Torvalds 78211da177e4SLinus Torvalds out_nfserr: 7822b8dd7b9aSAl Viro status = nfserrno(err); 7823eb82dd39SJeff Layton goto put_file; 78241da177e4SLinus Torvalds } 78251da177e4SLinus Torvalds 78261da177e4SLinus Torvalds /* 78271da177e4SLinus Torvalds * returns 7828f9c00c3aSJeff Layton * true: locks held by lockowner 7829f9c00c3aSJeff Layton * false: no locks held by lockowner 78301da177e4SLinus Torvalds */ 7831f9c00c3aSJeff Layton static bool 7832f9c00c3aSJeff Layton check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) 78331da177e4SLinus Torvalds { 7834bd61e0a9SJeff Layton struct file_lock *fl; 7835f9c00c3aSJeff Layton int status = false; 7836eb82dd39SJeff Layton struct nfsd_file *nf = find_any_file(fp); 7837f9c00c3aSJeff Layton struct inode *inode; 7838bd61e0a9SJeff Layton struct file_lock_context *flctx; 7839f9c00c3aSJeff Layton 7840eb82dd39SJeff Layton if (!nf) { 7841f9c00c3aSJeff Layton /* Any valid lock stateid should have some sort of access */ 7842f9c00c3aSJeff Layton WARN_ON_ONCE(1); 7843f9c00c3aSJeff Layton return status; 7844f9c00c3aSJeff Layton } 7845f9c00c3aSJeff Layton 7846c65454a9SJeff Layton inode = file_inode(nf->nf_file); 784777c67530SJeff Layton flctx = locks_inode_context(inode); 78481da177e4SLinus Torvalds 7849bd61e0a9SJeff Layton if (flctx && !list_empty_careful(&flctx->flc_posix)) { 78506109c850SJeff Layton spin_lock(&flctx->flc_lock); 7851bd61e0a9SJeff Layton list_for_each_entry(fl, &flctx->flc_posix, fl_list) { 7852bd61e0a9SJeff Layton if (fl->fl_owner == (fl_owner_t)lowner) { 7853f9c00c3aSJeff Layton status = true; 7854f9c00c3aSJeff Layton break; 78551da177e4SLinus Torvalds } 7856796dadfdSJ. Bruce Fields } 78576109c850SJeff Layton spin_unlock(&flctx->flc_lock); 7858bd61e0a9SJeff Layton } 7859eb82dd39SJeff Layton nfsd_file_put(nf); 78601da177e4SLinus Torvalds return status; 78611da177e4SLinus Torvalds } 78621da177e4SLinus Torvalds 7863043862b0SChuck Lever /** 7864043862b0SChuck Lever * nfsd4_release_lockowner - process NFSv4.0 RELEASE_LOCKOWNER operations 7865043862b0SChuck Lever * @rqstp: RPC transaction 7866043862b0SChuck Lever * @cstate: NFSv4 COMPOUND state 7867043862b0SChuck Lever * @u: RELEASE_LOCKOWNER arguments 7868043862b0SChuck Lever * 7869043862b0SChuck Lever * The lockowner's so_count is bumped when a lock record is added 7870043862b0SChuck Lever * or when copying a conflicting lock. The latter case is brief, 7871043862b0SChuck Lever * but can lead to fleeting false positives when looking for 7872043862b0SChuck Lever * locks-in-use. 7873043862b0SChuck Lever * 7874043862b0SChuck Lever * Return values: 7875043862b0SChuck Lever * %nfs_ok: lockowner released or not found 7876043862b0SChuck Lever * %nfserr_locks_held: lockowner still in use 7877043862b0SChuck Lever * %nfserr_stale_clientid: clientid no longer active 7878043862b0SChuck Lever * %nfserr_expired: clientid not recognized 7879043862b0SChuck Lever */ 7880b37ad28bSAl Viro __be32 7881b591480bSJ.Bruce Fields nfsd4_release_lockowner(struct svc_rqst *rqstp, 7882b591480bSJ.Bruce Fields struct nfsd4_compound_state *cstate, 7883eb69853dSChristoph Hellwig union nfsd4_op_u *u) 78841da177e4SLinus Torvalds { 7885eb69853dSChristoph Hellwig struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; 78867f2210faSStanislav Kinsbursky struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 7887bd8fdb6eSChuck Lever clientid_t *clid = &rlockowner->rl_clientid; 7888bd8fdb6eSChuck Lever struct nfs4_ol_stateid *stp; 7889bd8fdb6eSChuck Lever struct nfs4_lockowner *lo; 7890c58c6610STrond Myklebust struct nfs4_client *clp; 789188584818SChuck Lever LIST_HEAD(reaplist); 7892bd8fdb6eSChuck Lever __be32 status; 78931da177e4SLinus Torvalds 78941da177e4SLinus Torvalds dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", 78951da177e4SLinus Torvalds clid->cl_boot, clid->cl_id); 78961da177e4SLinus Torvalds 7897f71475baSJ. Bruce Fields status = set_client(clid, cstate, nn); 78989b2ef62bSJ. Bruce Fields if (status) 789951f5e783STrond Myklebust return status; 7900d4f0489fSTrond Myklebust clp = cstate->clp; 7901bd8fdb6eSChuck Lever 7902d4f0489fSTrond Myklebust spin_lock(&clp->cl_lock); 7903bd8fdb6eSChuck Lever lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner); 790488584818SChuck Lever if (!lo) { 7905d4f0489fSTrond Myklebust spin_unlock(&clp->cl_lock); 7906043862b0SChuck Lever return nfs_ok; 790788584818SChuck Lever } 7908bd8fdb6eSChuck Lever if (atomic_read(&lo->lo_owner.so_count) != 2) { 7909bd8fdb6eSChuck Lever spin_unlock(&clp->cl_lock); 7910bd8fdb6eSChuck Lever nfs4_put_stateowner(&lo->lo_owner); 7911bd8fdb6eSChuck Lever return nfserr_locks_held; 7912bd8fdb6eSChuck Lever } 791388584818SChuck Lever unhash_lockowner_locked(lo); 791488584818SChuck Lever while (!list_empty(&lo->lo_owner.so_stateids)) { 791588584818SChuck Lever stp = list_first_entry(&lo->lo_owner.so_stateids, 791688584818SChuck Lever struct nfs4_ol_stateid, 791788584818SChuck Lever st_perstateowner); 791888584818SChuck Lever WARN_ON(!unhash_lock_stateid(stp)); 791988584818SChuck Lever put_ol_stateid_locked(stp, &reaplist); 792088584818SChuck Lever } 792188584818SChuck Lever spin_unlock(&clp->cl_lock); 7922043862b0SChuck Lever 792388584818SChuck Lever free_ol_stateid_reaplist(&reaplist); 792468ef3bc3SJeff Layton remove_blocked_locks(lo); 792588584818SChuck Lever nfs4_put_stateowner(&lo->lo_owner); 7926043862b0SChuck Lever return nfs_ok; 79271da177e4SLinus Torvalds } 79281da177e4SLinus Torvalds 79291da177e4SLinus Torvalds static inline struct nfs4_client_reclaim * 7930a55370a3SNeilBrown alloc_reclaim(void) 79311da177e4SLinus Torvalds { 7932a55370a3SNeilBrown return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); 79331da177e4SLinus Torvalds } 79341da177e4SLinus Torvalds 79350ce0c2b5SJeff Layton bool 79366b189105SScott Mayhew nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn) 7937c7b9a459SNeilBrown { 79380ce0c2b5SJeff Layton struct nfs4_client_reclaim *crp; 7939c7b9a459SNeilBrown 794052e19c09SStanislav Kinsbursky crp = nfsd4_find_reclaim_client(name, nn); 79410ce0c2b5SJeff Layton return (crp && crp->cr_clp); 7942c7b9a459SNeilBrown } 7943c7b9a459SNeilBrown 79441da177e4SLinus Torvalds /* 79451da177e4SLinus Torvalds * failure => all reset bets are off, nfserr_no_grace... 79466b189105SScott Mayhew * 79476b189105SScott Mayhew * The caller is responsible for freeing name.data if NULL is returned (it 79486b189105SScott Mayhew * will be freed in nfs4_remove_reclaim_record in the normal case). 79491da177e4SLinus Torvalds */ 7950772a9bbbSJeff Layton struct nfs4_client_reclaim * 79516ee95d1cSScott Mayhew nfs4_client_to_reclaim(struct xdr_netobj name, struct xdr_netobj princhash, 79526ee95d1cSScott Mayhew struct nfsd_net *nn) 79531da177e4SLinus Torvalds { 79541da177e4SLinus Torvalds unsigned int strhashval; 7955772a9bbbSJeff Layton struct nfs4_client_reclaim *crp; 79561da177e4SLinus Torvalds 7957a55370a3SNeilBrown crp = alloc_reclaim(); 7958772a9bbbSJeff Layton if (crp) { 7959a55370a3SNeilBrown strhashval = clientstr_hashval(name); 79601da177e4SLinus Torvalds INIT_LIST_HEAD(&crp->cr_strhash); 796152e19c09SStanislav Kinsbursky list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); 79626b189105SScott Mayhew crp->cr_name.data = name.data; 79636b189105SScott Mayhew crp->cr_name.len = name.len; 79646ee95d1cSScott Mayhew crp->cr_princhash.data = princhash.data; 79656ee95d1cSScott Mayhew crp->cr_princhash.len = princhash.len; 79660ce0c2b5SJeff Layton crp->cr_clp = NULL; 796752e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size++; 7968772a9bbbSJeff Layton } 7969772a9bbbSJeff Layton return crp; 79701da177e4SLinus Torvalds } 79711da177e4SLinus Torvalds 79722a4317c5SJeff Layton void 797352e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) 7974ce30e539SJeff Layton { 7975ce30e539SJeff Layton list_del(&crp->cr_strhash); 79766b189105SScott Mayhew kfree(crp->cr_name.data); 79776ee95d1cSScott Mayhew kfree(crp->cr_princhash.data); 7978ce30e539SJeff Layton kfree(crp); 797952e19c09SStanislav Kinsbursky nn->reclaim_str_hashtbl_size--; 7980ce30e539SJeff Layton } 7981ce30e539SJeff Layton 7982ce30e539SJeff Layton void 798352e19c09SStanislav Kinsbursky nfs4_release_reclaim(struct nfsd_net *nn) 79841da177e4SLinus Torvalds { 79851da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 79861da177e4SLinus Torvalds int i; 79871da177e4SLinus Torvalds 79881da177e4SLinus Torvalds for (i = 0; i < CLIENT_HASH_SIZE; i++) { 798952e19c09SStanislav Kinsbursky while (!list_empty(&nn->reclaim_str_hashtbl[i])) { 799052e19c09SStanislav Kinsbursky crp = list_entry(nn->reclaim_str_hashtbl[i].next, 79911da177e4SLinus Torvalds struct nfs4_client_reclaim, cr_strhash); 799252e19c09SStanislav Kinsbursky nfs4_remove_reclaim_record(crp, nn); 79931da177e4SLinus Torvalds } 79941da177e4SLinus Torvalds } 7995063b0fb9SJ. Bruce Fields WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); 79961da177e4SLinus Torvalds } 79971da177e4SLinus Torvalds 79981da177e4SLinus Torvalds /* 79991da177e4SLinus Torvalds * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ 80002a4317c5SJeff Layton struct nfs4_client_reclaim * 80016b189105SScott Mayhew nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) 80021da177e4SLinus Torvalds { 80031da177e4SLinus Torvalds unsigned int strhashval; 80041da177e4SLinus Torvalds struct nfs4_client_reclaim *crp = NULL; 80051da177e4SLinus Torvalds 80066b189105SScott Mayhew strhashval = clientstr_hashval(name); 800752e19c09SStanislav Kinsbursky list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { 80086b189105SScott Mayhew if (compare_blob(&crp->cr_name, &name) == 0) { 80091da177e4SLinus Torvalds return crp; 80101da177e4SLinus Torvalds } 80111da177e4SLinus Torvalds } 80121da177e4SLinus Torvalds return NULL; 80131da177e4SLinus Torvalds } 80141da177e4SLinus Torvalds 8015b37ad28bSAl Viro __be32 80161722b046SJ. Bruce Fields nfs4_check_open_reclaim(struct nfs4_client *clp) 80171da177e4SLinus Torvalds { 80181722b046SJ. Bruce Fields if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) 80193b3e7b72SJeff Layton return nfserr_no_grace; 80203b3e7b72SJeff Layton 80211722b046SJ. Bruce Fields if (nfsd4_client_record_check(clp)) 80220fe492dbSTrond Myklebust return nfserr_reclaim_bad; 80230fe492dbSTrond Myklebust 80240fe492dbSTrond Myklebust return nfs_ok; 80251da177e4SLinus Torvalds } 80261da177e4SLinus Torvalds 8027c2f1a551SMeelap Shah /* 8028c2f1a551SMeelap Shah * Since the lifetime of a delegation isn't limited to that of an open, a 8029c2f1a551SMeelap Shah * client may quite reasonably hang on to a delegation as long as it has 8030c2f1a551SMeelap Shah * the inode cached. This becomes an obvious problem the first time a 8031c2f1a551SMeelap Shah * client's inode cache approaches the size of the server's total memory. 8032c2f1a551SMeelap Shah * 8033c2f1a551SMeelap Shah * For now we avoid this problem by imposing a hard limit on the number 8034c2f1a551SMeelap Shah * of delegations, which varies according to the server's memory size. 8035c2f1a551SMeelap Shah */ 8036c2f1a551SMeelap Shah static void 8037c2f1a551SMeelap Shah set_max_delegations(void) 8038c2f1a551SMeelap Shah { 8039c2f1a551SMeelap Shah /* 8040c2f1a551SMeelap Shah * Allow at most 4 delegations per megabyte of RAM. Quick 8041c2f1a551SMeelap Shah * estimates suggest that in the worst case (where every delegation 8042c2f1a551SMeelap Shah * is for a different inode), a delegation could take about 1.5K, 8043c2f1a551SMeelap Shah * giving a worst case usage of about 6% of memory. 8044c2f1a551SMeelap Shah */ 8045c2f1a551SMeelap Shah max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); 8046c2f1a551SMeelap Shah } 8047c2f1a551SMeelap Shah 8048d85ed443SStanislav Kinsbursky static int nfs4_state_create_net(struct net *net) 80498daae4dcSStanislav Kinsbursky { 80508daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 80518daae4dcSStanislav Kinsbursky int i; 80528daae4dcSStanislav Kinsbursky 80536da2ec56SKees Cook nn->conf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 80546da2ec56SKees Cook sizeof(struct list_head), 80556da2ec56SKees Cook GFP_KERNEL); 80568daae4dcSStanislav Kinsbursky if (!nn->conf_id_hashtbl) 8057382a62e7SStanislav Kinsbursky goto err; 80586da2ec56SKees Cook nn->unconf_id_hashtbl = kmalloc_array(CLIENT_HASH_SIZE, 80596da2ec56SKees Cook sizeof(struct list_head), 80606da2ec56SKees Cook GFP_KERNEL); 80610a7ec377SStanislav Kinsbursky if (!nn->unconf_id_hashtbl) 80620a7ec377SStanislav Kinsbursky goto err_unconf_id; 80636da2ec56SKees Cook nn->sessionid_hashtbl = kmalloc_array(SESSION_HASH_SIZE, 80646da2ec56SKees Cook sizeof(struct list_head), 80656da2ec56SKees Cook GFP_KERNEL); 80661872de0eSStanislav Kinsbursky if (!nn->sessionid_hashtbl) 80671872de0eSStanislav Kinsbursky goto err_sessionid; 80688daae4dcSStanislav Kinsbursky 8069382a62e7SStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 80708daae4dcSStanislav Kinsbursky INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); 80710a7ec377SStanislav Kinsbursky INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); 8072382a62e7SStanislav Kinsbursky } 80731872de0eSStanislav Kinsbursky for (i = 0; i < SESSION_HASH_SIZE; i++) 80741872de0eSStanislav Kinsbursky INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); 8075382a62e7SStanislav Kinsbursky nn->conf_name_tree = RB_ROOT; 8076a99454aaSStanislav Kinsbursky nn->unconf_name_tree = RB_ROOT; 80779cc76801SArnd Bergmann nn->boot_time = ktime_get_real_seconds(); 807881833de1SVasily Averin nn->grace_ended = false; 807981833de1SVasily Averin nn->nfsd4_manager.block_opens = true; 808081833de1SVasily Averin INIT_LIST_HEAD(&nn->nfsd4_manager.list); 80815ed58bb2SStanislav Kinsbursky INIT_LIST_HEAD(&nn->client_lru); 808273758fedSStanislav Kinsbursky INIT_LIST_HEAD(&nn->close_lru); 8083e8c69d17SJ. Bruce Fields INIT_LIST_HEAD(&nn->del_recall_lru); 8084c9a49628SStanislav Kinsbursky spin_lock_init(&nn->client_lock); 8085e0639dc5SOlga Kornievskaia spin_lock_init(&nn->s2s_cp_lock); 8086e0639dc5SOlga Kornievskaia idr_init(&nn->s2s_cp_stateids); 80878daae4dcSStanislav Kinsbursky 80880cc11a61SJeff Layton spin_lock_init(&nn->blocked_locks_lock); 80890cc11a61SJeff Layton INIT_LIST_HEAD(&nn->blocked_locks_lru); 80900cc11a61SJeff Layton 809109121281SStanislav Kinsbursky INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); 80927c24fa22SDai Ngo INIT_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker); 8093d85ed443SStanislav Kinsbursky get_net(net); 809409121281SStanislav Kinsbursky 8095f385f7d2SDai Ngo nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan; 8096f385f7d2SDai Ngo nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count; 8097f385f7d2SDai Ngo nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS; 8098f385f7d2SDai Ngo 8099f385f7d2SDai Ngo if (register_shrinker(&nn->nfsd_client_shrinker, "nfsd-client")) 8100f385f7d2SDai Ngo goto err_shrinker; 81018daae4dcSStanislav Kinsbursky return 0; 8102382a62e7SStanislav Kinsbursky 8103f385f7d2SDai Ngo err_shrinker: 8104f385f7d2SDai Ngo put_net(net); 8105f385f7d2SDai Ngo kfree(nn->sessionid_hashtbl); 81061872de0eSStanislav Kinsbursky err_sessionid: 81079b531137SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 81080a7ec377SStanislav Kinsbursky err_unconf_id: 81090a7ec377SStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 8110382a62e7SStanislav Kinsbursky err: 8111382a62e7SStanislav Kinsbursky return -ENOMEM; 81128daae4dcSStanislav Kinsbursky } 81138daae4dcSStanislav Kinsbursky 81148daae4dcSStanislav Kinsbursky static void 81154dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(struct net *net) 81168daae4dcSStanislav Kinsbursky { 81178daae4dcSStanislav Kinsbursky int i; 81188daae4dcSStanislav Kinsbursky struct nfs4_client *clp = NULL; 81198daae4dcSStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 81208daae4dcSStanislav Kinsbursky 81218daae4dcSStanislav Kinsbursky for (i = 0; i < CLIENT_HASH_SIZE; i++) { 81228daae4dcSStanislav Kinsbursky while (!list_empty(&nn->conf_id_hashtbl[i])) { 81238daae4dcSStanislav Kinsbursky clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 81248daae4dcSStanislav Kinsbursky destroy_client(clp); 81258daae4dcSStanislav Kinsbursky } 81268daae4dcSStanislav Kinsbursky } 8127a99454aaSStanislav Kinsbursky 812868ef3bc3SJeff Layton WARN_ON(!list_empty(&nn->blocked_locks_lru)); 812968ef3bc3SJeff Layton 81302b905635SKinglong Mee for (i = 0; i < CLIENT_HASH_SIZE; i++) { 81312b905635SKinglong Mee while (!list_empty(&nn->unconf_id_hashtbl[i])) { 81322b905635SKinglong Mee clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); 8133a99454aaSStanislav Kinsbursky destroy_client(clp); 8134a99454aaSStanislav Kinsbursky } 81352b905635SKinglong Mee } 8136a99454aaSStanislav Kinsbursky 81371872de0eSStanislav Kinsbursky kfree(nn->sessionid_hashtbl); 81380a7ec377SStanislav Kinsbursky kfree(nn->unconf_id_hashtbl); 81398daae4dcSStanislav Kinsbursky kfree(nn->conf_id_hashtbl); 81404dce0ac9SStanislav Kinsbursky put_net(net); 81418daae4dcSStanislav Kinsbursky } 81428daae4dcSStanislav Kinsbursky 8143f252bc68SStanislav Kinsbursky int 8144d85ed443SStanislav Kinsbursky nfs4_state_start_net(struct net *net) 8145ac4d8ff2SNeilBrown { 81465e1533c7SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 8147b5a1a81eSJ. Bruce Fields int ret; 8148b5a1a81eSJ. Bruce Fields 8149c6c7f2a8STrond Myklebust ret = nfs4_state_create_net(net); 81508daae4dcSStanislav Kinsbursky if (ret) 81518daae4dcSStanislav Kinsbursky return ret; 8152d4318acdSJeff Layton locks_start_grace(net, &nn->nfsd4_manager); 8153d4318acdSJeff Layton nfsd4_client_tracking_init(net); 8154362063a5SScott Mayhew if (nn->track_reclaim_completes && nn->reclaim_str_hashtbl_size == 0) 8155362063a5SScott Mayhew goto skip_grace; 815620b7d86fSArnd Bergmann printk(KERN_INFO "NFSD: starting %lld-second grace period (net %x)\n", 81577e981a8aSVasily Averin nn->nfsd4_grace, net->ns.inum); 8158dd5e3fbcSChuck Lever trace_nfsd_grace_start(nn); 81595284b44eSStanislav Kinsbursky queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); 8160d85ed443SStanislav Kinsbursky return 0; 8161362063a5SScott Mayhew 8162362063a5SScott Mayhew skip_grace: 8163362063a5SScott Mayhew printk(KERN_INFO "NFSD: no clients to reclaim, skipping NFSv4 grace period (net %x)\n", 8164362063a5SScott Mayhew net->ns.inum); 8165362063a5SScott Mayhew queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_lease * HZ); 8166362063a5SScott Mayhew nfsd4_end_grace(nn); 8167362063a5SScott Mayhew return 0; 8168a6d6b781SJeff Layton } 8169d85ed443SStanislav Kinsbursky 8170d85ed443SStanislav Kinsbursky /* initialization to perform when the nfsd service is started: */ 8171d85ed443SStanislav Kinsbursky 8172d85ed443SStanislav Kinsbursky int 8173d85ed443SStanislav Kinsbursky nfs4_state_start(void) 8174d85ed443SStanislav Kinsbursky { 8175d85ed443SStanislav Kinsbursky int ret; 8176d85ed443SStanislav Kinsbursky 8177d47b295eSChuck Lever ret = rhltable_init(&nfs4_file_rhltable, &nfs4_file_rhash_params); 8178b5a1a81eSJ. Bruce Fields if (ret) 8179d76cc46bSDai Ngo return ret; 818009121281SStanislav Kinsbursky 8181d47b295eSChuck Lever ret = nfsd4_create_callback_queue(); 8182d47b295eSChuck Lever if (ret) { 8183d47b295eSChuck Lever rhltable_destroy(&nfs4_file_rhltable); 8184d47b295eSChuck Lever return ret; 8185d47b295eSChuck Lever } 8186d47b295eSChuck Lever 8187c2f1a551SMeelap Shah set_max_delegations(); 8188b5a1a81eSJ. Bruce Fields return 0; 81891da177e4SLinus Torvalds } 81901da177e4SLinus Torvalds 8191f252bc68SStanislav Kinsbursky void 81924dce0ac9SStanislav Kinsbursky nfs4_state_shutdown_net(struct net *net) 81931da177e4SLinus Torvalds { 81941da177e4SLinus Torvalds struct nfs4_delegation *dp = NULL; 81951da177e4SLinus Torvalds struct list_head *pos, *next, reaplist; 81964dce0ac9SStanislav Kinsbursky struct nfsd_net *nn = net_generic(net, nfsd_net_id); 81971da177e4SLinus Torvalds 8198f385f7d2SDai Ngo unregister_shrinker(&nn->nfsd_client_shrinker); 81997c24fa22SDai Ngo cancel_work(&nn->nfsd_shrinker_work); 82004dce0ac9SStanislav Kinsbursky cancel_delayed_work_sync(&nn->laundromat_work); 82014dce0ac9SStanislav Kinsbursky locks_end_grace(&nn->nfsd4_manager); 8202ac55fdc4SJeff Layton 82031da177e4SLinus Torvalds INIT_LIST_HEAD(&reaplist); 8204cdc97505SBenny Halevy spin_lock(&state_lock); 8205e8c69d17SJ. Bruce Fields list_for_each_safe(pos, next, &nn->del_recall_lru) { 82061da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 82073fcbbd24SJeff Layton WARN_ON(!unhash_delegation_locked(dp)); 820842690676SJeff Layton list_add(&dp->dl_recall_lru, &reaplist); 82091da177e4SLinus Torvalds } 8210cdc97505SBenny Halevy spin_unlock(&state_lock); 82111da177e4SLinus Torvalds list_for_each_safe(pos, next, &reaplist) { 82121da177e4SLinus Torvalds dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 821342690676SJeff Layton list_del_init(&dp->dl_recall_lru); 82140af6e690SJ. Bruce Fields destroy_unhashed_deleg(dp); 82151da177e4SLinus Torvalds } 82161da177e4SLinus Torvalds 82173320fef1SStanislav Kinsbursky nfsd4_client_tracking_exit(net); 82184dce0ac9SStanislav Kinsbursky nfs4_state_destroy_net(net); 8219f4e44b39SDai Ngo #ifdef CONFIG_NFSD_V4_2_INTER_SSC 8220f4e44b39SDai Ngo nfsd4_ssc_shutdown_umount(nn); 8221f4e44b39SDai Ngo #endif 82221da177e4SLinus Torvalds } 82231da177e4SLinus Torvalds 82241da177e4SLinus Torvalds void 82251da177e4SLinus Torvalds nfs4_state_shutdown(void) 82261da177e4SLinus Torvalds { 8227c3935e30SJ. Bruce Fields nfsd4_destroy_callback_queue(); 82284102db17SJeff Layton rhltable_destroy(&nfs4_file_rhltable); 82291da177e4SLinus Torvalds } 82308b70484cSTigran Mkrtchyan 82318b70484cSTigran Mkrtchyan static void 82328b70484cSTigran Mkrtchyan get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 82338b70484cSTigran Mkrtchyan { 823451100d2bSOlga Kornievskaia if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG) && 823551100d2bSOlga Kornievskaia CURRENT_STATEID(stateid)) 823637c593c5STigran Mkrtchyan memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); 82378b70484cSTigran Mkrtchyan } 82388b70484cSTigran Mkrtchyan 82398b70484cSTigran Mkrtchyan static void 82408b70484cSTigran Mkrtchyan put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) 82418b70484cSTigran Mkrtchyan { 824237c593c5STigran Mkrtchyan if (cstate->minorversion) { 824337c593c5STigran Mkrtchyan memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); 824451100d2bSOlga Kornievskaia SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 824537c593c5STigran Mkrtchyan } 824637c593c5STigran Mkrtchyan } 824737c593c5STigran Mkrtchyan 824837c593c5STigran Mkrtchyan void 824937c593c5STigran Mkrtchyan clear_current_stateid(struct nfsd4_compound_state *cstate) 825037c593c5STigran Mkrtchyan { 825151100d2bSOlga Kornievskaia CLEAR_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG); 82528b70484cSTigran Mkrtchyan } 82538b70484cSTigran Mkrtchyan 825462cd4a59STigran Mkrtchyan /* 825562cd4a59STigran Mkrtchyan * functions to set current state id 825662cd4a59STigran Mkrtchyan */ 82578b70484cSTigran Mkrtchyan void 8258b60e9859SChristoph Hellwig nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, 8259b60e9859SChristoph Hellwig union nfsd4_op_u *u) 82609428fe1aSTigran Mkrtchyan { 8261b60e9859SChristoph Hellwig put_stateid(cstate, &u->open_downgrade.od_stateid); 82629428fe1aSTigran Mkrtchyan } 82639428fe1aSTigran Mkrtchyan 82649428fe1aSTigran Mkrtchyan void 8265b60e9859SChristoph Hellwig nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, 8266b60e9859SChristoph Hellwig union nfsd4_op_u *u) 82678b70484cSTigran Mkrtchyan { 8268b60e9859SChristoph Hellwig put_stateid(cstate, &u->open.op_stateid); 82698b70484cSTigran Mkrtchyan } 82708b70484cSTigran Mkrtchyan 82718b70484cSTigran Mkrtchyan void 8272b60e9859SChristoph Hellwig nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, 8273b60e9859SChristoph Hellwig union nfsd4_op_u *u) 827462cd4a59STigran Mkrtchyan { 8275b60e9859SChristoph Hellwig put_stateid(cstate, &u->close.cl_stateid); 827662cd4a59STigran Mkrtchyan } 827762cd4a59STigran Mkrtchyan 827862cd4a59STigran Mkrtchyan void 8279b60e9859SChristoph Hellwig nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, 8280b60e9859SChristoph Hellwig union nfsd4_op_u *u) 828162cd4a59STigran Mkrtchyan { 8282b60e9859SChristoph Hellwig put_stateid(cstate, &u->lock.lk_resp_stateid); 828362cd4a59STigran Mkrtchyan } 828462cd4a59STigran Mkrtchyan 828562cd4a59STigran Mkrtchyan /* 828662cd4a59STigran Mkrtchyan * functions to consume current state id 828762cd4a59STigran Mkrtchyan */ 82881e97b519STigran Mkrtchyan 82891e97b519STigran Mkrtchyan void 829057832e7bSChristoph Hellwig nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, 829157832e7bSChristoph Hellwig union nfsd4_op_u *u) 82929428fe1aSTigran Mkrtchyan { 829357832e7bSChristoph Hellwig get_stateid(cstate, &u->open_downgrade.od_stateid); 82949428fe1aSTigran Mkrtchyan } 82959428fe1aSTigran Mkrtchyan 82969428fe1aSTigran Mkrtchyan void 829757832e7bSChristoph Hellwig nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, 829857832e7bSChristoph Hellwig union nfsd4_op_u *u) 82999428fe1aSTigran Mkrtchyan { 830057832e7bSChristoph Hellwig get_stateid(cstate, &u->delegreturn.dr_stateid); 83019428fe1aSTigran Mkrtchyan } 83029428fe1aSTigran Mkrtchyan 83039428fe1aSTigran Mkrtchyan void 830457832e7bSChristoph Hellwig nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, 830557832e7bSChristoph Hellwig union nfsd4_op_u *u) 83061e97b519STigran Mkrtchyan { 830757832e7bSChristoph Hellwig get_stateid(cstate, &u->free_stateid.fr_stateid); 83081e97b519STigran Mkrtchyan } 83091e97b519STigran Mkrtchyan 83101e97b519STigran Mkrtchyan void 831157832e7bSChristoph Hellwig nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, 831257832e7bSChristoph Hellwig union nfsd4_op_u *u) 83131e97b519STigran Mkrtchyan { 831457832e7bSChristoph Hellwig get_stateid(cstate, &u->setattr.sa_stateid); 83151e97b519STigran Mkrtchyan } 83161e97b519STigran Mkrtchyan 831762cd4a59STigran Mkrtchyan void 831857832e7bSChristoph Hellwig nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, 831957832e7bSChristoph Hellwig union nfsd4_op_u *u) 83208b70484cSTigran Mkrtchyan { 832157832e7bSChristoph Hellwig get_stateid(cstate, &u->close.cl_stateid); 83228b70484cSTigran Mkrtchyan } 83238b70484cSTigran Mkrtchyan 83248b70484cSTigran Mkrtchyan void 832557832e7bSChristoph Hellwig nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, 832657832e7bSChristoph Hellwig union nfsd4_op_u *u) 83278b70484cSTigran Mkrtchyan { 832857832e7bSChristoph Hellwig get_stateid(cstate, &u->locku.lu_stateid); 83298b70484cSTigran Mkrtchyan } 833030813e27STigran Mkrtchyan 833130813e27STigran Mkrtchyan void 833257832e7bSChristoph Hellwig nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, 833357832e7bSChristoph Hellwig union nfsd4_op_u *u) 833430813e27STigran Mkrtchyan { 833557832e7bSChristoph Hellwig get_stateid(cstate, &u->read.rd_stateid); 833630813e27STigran Mkrtchyan } 833730813e27STigran Mkrtchyan 833830813e27STigran Mkrtchyan void 833957832e7bSChristoph Hellwig nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, 834057832e7bSChristoph Hellwig union nfsd4_op_u *u) 834130813e27STigran Mkrtchyan { 834257832e7bSChristoph Hellwig get_stateid(cstate, &u->write.wr_stateid); 834330813e27STigran Mkrtchyan } 8344*fd19ca36SDai Ngo 8345*fd19ca36SDai Ngo /** 8346*fd19ca36SDai Ngo * nfsd4_deleg_getattr_conflict - Recall if GETATTR causes conflict 8347*fd19ca36SDai Ngo * @rqstp: RPC transaction context 8348*fd19ca36SDai Ngo * @inode: file to be checked for a conflict 8349*fd19ca36SDai Ngo * 8350*fd19ca36SDai Ngo * This function is called when there is a conflict between a write 8351*fd19ca36SDai Ngo * delegation and a change/size GETATTR from another client. The server 8352*fd19ca36SDai Ngo * must either use the CB_GETATTR to get the current values of the 8353*fd19ca36SDai Ngo * attributes from the client that holds the delegation or recall the 8354*fd19ca36SDai Ngo * delegation before replying to the GETATTR. See RFC 8881 section 8355*fd19ca36SDai Ngo * 18.7.4. 8356*fd19ca36SDai Ngo * 8357*fd19ca36SDai Ngo * The current implementation does not support CB_GETATTR yet. However 8358*fd19ca36SDai Ngo * this can avoid recalling the delegation could be added in follow up 8359*fd19ca36SDai Ngo * work. 8360*fd19ca36SDai Ngo * 8361*fd19ca36SDai Ngo * Returns 0 if there is no conflict; otherwise an nfs_stat 8362*fd19ca36SDai Ngo * code is returned. 8363*fd19ca36SDai Ngo */ 8364*fd19ca36SDai Ngo __be32 8365*fd19ca36SDai Ngo nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct inode *inode) 8366*fd19ca36SDai Ngo { 8367*fd19ca36SDai Ngo __be32 status; 8368*fd19ca36SDai Ngo struct file_lock_context *ctx; 8369*fd19ca36SDai Ngo struct file_lock *fl; 8370*fd19ca36SDai Ngo struct nfs4_delegation *dp; 8371*fd19ca36SDai Ngo 8372*fd19ca36SDai Ngo ctx = locks_inode_context(inode); 8373*fd19ca36SDai Ngo if (!ctx) 8374*fd19ca36SDai Ngo return 0; 8375*fd19ca36SDai Ngo spin_lock(&ctx->flc_lock); 8376*fd19ca36SDai Ngo list_for_each_entry(fl, &ctx->flc_lease, fl_list) { 8377*fd19ca36SDai Ngo if (fl->fl_flags == FL_LAYOUT) 8378*fd19ca36SDai Ngo continue; 8379*fd19ca36SDai Ngo if (fl->fl_lmops != &nfsd_lease_mng_ops) { 8380*fd19ca36SDai Ngo /* 8381*fd19ca36SDai Ngo * non-nfs lease, if it's a lease with F_RDLCK then 8382*fd19ca36SDai Ngo * we are done; there isn't any write delegation 8383*fd19ca36SDai Ngo * on this inode 8384*fd19ca36SDai Ngo */ 8385*fd19ca36SDai Ngo if (fl->fl_type == F_RDLCK) 8386*fd19ca36SDai Ngo break; 8387*fd19ca36SDai Ngo goto break_lease; 8388*fd19ca36SDai Ngo } 8389*fd19ca36SDai Ngo if (fl->fl_type == F_WRLCK) { 8390*fd19ca36SDai Ngo dp = fl->fl_owner; 8391*fd19ca36SDai Ngo if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) { 8392*fd19ca36SDai Ngo spin_unlock(&ctx->flc_lock); 8393*fd19ca36SDai Ngo return 0; 8394*fd19ca36SDai Ngo } 8395*fd19ca36SDai Ngo break_lease: 8396*fd19ca36SDai Ngo spin_unlock(&ctx->flc_lock); 8397*fd19ca36SDai Ngo nfsd_stats_wdeleg_getattr_inc(); 8398*fd19ca36SDai Ngo status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); 8399*fd19ca36SDai Ngo if (status != nfserr_jukebox || 8400*fd19ca36SDai Ngo !nfsd_wait_for_delegreturn(rqstp, inode)) 8401*fd19ca36SDai Ngo return status; 8402*fd19ca36SDai Ngo return 0; 8403*fd19ca36SDai Ngo } 8404*fd19ca36SDai Ngo break; 8405*fd19ca36SDai Ngo } 8406*fd19ca36SDai Ngo spin_unlock(&ctx->flc_lock); 8407*fd19ca36SDai Ngo return 0; 8408*fd19ca36SDai Ngo } 8409