xref: /illumos-gate/usr/src/uts/common/fs/nfs/nfs4_state.c (revision f44e1126)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5cee86682Scalum  * Common Development and Distribution License (the "License").
6cee86682Scalum  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
210dfe541eSEvan Layton 
227c478bd9Sstevel@tonic-gate /*
23eec118a1SMarcel Telka  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
240dfe541eSEvan Layton  */
250dfe541eSEvan Layton 
260dfe541eSEvan Layton /*
270dfe541eSEvan Layton  * Copyright 2018 Nexenta Systems, Inc.
280dfe541eSEvan Layton  * Copyright 2019 Nexenta by DDN, Inc.
29*f44e1126SVitaliy Gusev  * Copyright 2020 RackTop Systems, Inc.
30967a528aSDan McDonald  * Copyright 2023 MNX Cloud, Inc.
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <sys/systm.h>
347c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
357c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
367c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
377c478bd9Sstevel@tonic-gate #include <sys/clconf.h>
387c478bd9Sstevel@tonic-gate #include <sys/cladm.h>
397c478bd9Sstevel@tonic-gate #include <sys/flock.h>
407c478bd9Sstevel@tonic-gate #include <nfs/export.h>
417c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
427c478bd9Sstevel@tonic-gate #include <nfs/nfs4.h>
437c478bd9Sstevel@tonic-gate #include <nfs/nfssys.h>
447c478bd9Sstevel@tonic-gate #include <nfs/lm.h>
457c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
46ed57cab9Srg #include <sys/sdt.h>
47cee86682Scalum #include <sys/nvpair.h>
487c478bd9Sstevel@tonic-gate 
49da6c28aaSamw extern u_longlong_t nfs4_srv_caller_id;
507c478bd9Sstevel@tonic-gate 
511b300de9Sjwahlig extern uint_t nfs4_srv_vkey;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate stateid4 special0 = {
547c478bd9Sstevel@tonic-gate 	0,
557c478bd9Sstevel@tonic-gate 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
567c478bd9Sstevel@tonic-gate };
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate stateid4 special1 = {
597c478bd9Sstevel@tonic-gate 	0xffffffff,
607c478bd9Sstevel@tonic-gate 	{
617c478bd9Sstevel@tonic-gate 		(char)0xff, (char)0xff, (char)0xff, (char)0xff,
627c478bd9Sstevel@tonic-gate 		(char)0xff, (char)0xff, (char)0xff, (char)0xff,
637c478bd9Sstevel@tonic-gate 		(char)0xff, (char)0xff, (char)0xff, (char)0xff
647c478bd9Sstevel@tonic-gate 	}
657c478bd9Sstevel@tonic-gate };
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	ISSPECIAL(id)  (stateid4_cmp(id, &special0) || \
697c478bd9Sstevel@tonic-gate 			stateid4_cmp(id, &special1))
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /* For embedding the cluster nodeid into our clientid */
727c478bd9Sstevel@tonic-gate #define	CLUSTER_NODEID_SHIFT	24
737c478bd9Sstevel@tonic-gate #define	CLUSTER_MAX_NODEID	255
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate #ifdef DEBUG
767c478bd9Sstevel@tonic-gate int rfs4_debug;
777c478bd9Sstevel@tonic-gate #endif
787c478bd9Sstevel@tonic-gate 
79aab20b47SToomas Soome rfs4_db_mem_cache_t rfs4_db_mem_cache_table[RFS4_DB_MEM_CACHE_NUM];
807c478bd9Sstevel@tonic-gate static uint32_t rfs4_database_debug = 0x00;
817c478bd9Sstevel@tonic-gate 
820dfe541eSEvan Layton /* CSTYLED */
830dfe541eSEvan Layton static void rfs4_ss_clid_write(nfs4_srv_t *nsrv4, rfs4_client_t *cp, char *leaf);
84cee86682Scalum static void rfs4_ss_clid_write_one(rfs4_client_t *cp, char *dir, char *leaf);
85cee86682Scalum static void rfs4_dss_clear_oldstate(rfs4_servinst_t *sip);
86cee86682Scalum static void rfs4_ss_chkclid_sip(rfs4_client_t *cp, rfs4_servinst_t *sip);
87cee86682Scalum 
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate  * Couple of simple init/destroy functions for a general waiter
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate void
rfs4_sw_init(rfs4_state_wait_t * swp)927c478bd9Sstevel@tonic-gate rfs4_sw_init(rfs4_state_wait_t *swp)
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate 	mutex_init(swp->sw_cv_lock, NULL, MUTEX_DEFAULT, NULL);
957c478bd9Sstevel@tonic-gate 	cv_init(swp->sw_cv, NULL, CV_DEFAULT, NULL);
967c478bd9Sstevel@tonic-gate 	swp->sw_active = FALSE;
977c478bd9Sstevel@tonic-gate 	swp->sw_wait_count = 0;
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate void
rfs4_sw_destroy(rfs4_state_wait_t * swp)1017c478bd9Sstevel@tonic-gate rfs4_sw_destroy(rfs4_state_wait_t *swp)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate 	mutex_destroy(swp->sw_cv_lock);
1047c478bd9Sstevel@tonic-gate 	cv_destroy(swp->sw_cv);
1057c478bd9Sstevel@tonic-gate }
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate void
rfs4_sw_enter(rfs4_state_wait_t * swp)1087c478bd9Sstevel@tonic-gate rfs4_sw_enter(rfs4_state_wait_t *swp)
1097c478bd9Sstevel@tonic-gate {
1107c478bd9Sstevel@tonic-gate 	mutex_enter(swp->sw_cv_lock);
1117c478bd9Sstevel@tonic-gate 	while (swp->sw_active) {
1127c478bd9Sstevel@tonic-gate 		swp->sw_wait_count++;
1137c478bd9Sstevel@tonic-gate 		cv_wait(swp->sw_cv, swp->sw_cv_lock);
1147c478bd9Sstevel@tonic-gate 		swp->sw_wait_count--;
1157c478bd9Sstevel@tonic-gate 	}
1167c478bd9Sstevel@tonic-gate 	ASSERT(swp->sw_active == FALSE);
1177c478bd9Sstevel@tonic-gate 	swp->sw_active = TRUE;
1187c478bd9Sstevel@tonic-gate 	mutex_exit(swp->sw_cv_lock);
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate void
rfs4_sw_exit(rfs4_state_wait_t * swp)1227c478bd9Sstevel@tonic-gate rfs4_sw_exit(rfs4_state_wait_t *swp)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	mutex_enter(swp->sw_cv_lock);
1257c478bd9Sstevel@tonic-gate 	ASSERT(swp->sw_active == TRUE);
1267c478bd9Sstevel@tonic-gate 	swp->sw_active = FALSE;
1277c478bd9Sstevel@tonic-gate 	if (swp->sw_wait_count != 0)
1287c478bd9Sstevel@tonic-gate 		cv_broadcast(swp->sw_cv);
1297c478bd9Sstevel@tonic-gate 	mutex_exit(swp->sw_cv_lock);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate static void
deep_lock_copy(LOCK4res * dres,LOCK4res * sres)1337c478bd9Sstevel@tonic-gate deep_lock_copy(LOCK4res *dres, LOCK4res *sres)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate 	lock_owner4 *slo = &sres->LOCK4res_u.denied.owner;
1367c478bd9Sstevel@tonic-gate 	lock_owner4 *dlo = &dres->LOCK4res_u.denied.owner;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (sres->status == NFS4ERR_DENIED) {
1397c478bd9Sstevel@tonic-gate 		dlo->owner_val = kmem_alloc(slo->owner_len, KM_SLEEP);
1407c478bd9Sstevel@tonic-gate 		bcopy(slo->owner_val, dlo->owner_val, slo->owner_len);
1417c478bd9Sstevel@tonic-gate 	}
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1440dfe541eSEvan Layton /*
1450dfe541eSEvan Layton  * CPR callback id -- not related to v4 callbacks
1460dfe541eSEvan Layton  */
1470dfe541eSEvan Layton static callb_id_t cpr_id = 0;
1480dfe541eSEvan Layton 
1497c478bd9Sstevel@tonic-gate static void
deep_lock_free(LOCK4res * res)1507c478bd9Sstevel@tonic-gate deep_lock_free(LOCK4res *res)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	lock_owner4 *lo = &res->LOCK4res_u.denied.owner;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	if (res->status == NFS4ERR_DENIED)
1557c478bd9Sstevel@tonic-gate 		kmem_free(lo->owner_val, lo->owner_len);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static void
deep_open_copy(OPEN4res * dres,OPEN4res * sres)1597c478bd9Sstevel@tonic-gate deep_open_copy(OPEN4res *dres, OPEN4res *sres)
1607c478bd9Sstevel@tonic-gate {
1617c478bd9Sstevel@tonic-gate 	nfsace4 *sacep, *dacep;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	if (sres->status != NFS4_OK) {
1647c478bd9Sstevel@tonic-gate 		return;
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	dres->attrset = sres->attrset;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	switch (sres->delegation.delegation_type) {
1707c478bd9Sstevel@tonic-gate 	case OPEN_DELEGATE_NONE:
1717c478bd9Sstevel@tonic-gate 		return;
1727c478bd9Sstevel@tonic-gate 	case OPEN_DELEGATE_READ:
1737c478bd9Sstevel@tonic-gate 		sacep = &sres->delegation.open_delegation4_u.read.permissions;
1747c478bd9Sstevel@tonic-gate 		dacep = &dres->delegation.open_delegation4_u.read.permissions;
1757c478bd9Sstevel@tonic-gate 		break;
1767c478bd9Sstevel@tonic-gate 	case OPEN_DELEGATE_WRITE:
1777c478bd9Sstevel@tonic-gate 		sacep = &sres->delegation.open_delegation4_u.write.permissions;
1787c478bd9Sstevel@tonic-gate 		dacep = &dres->delegation.open_delegation4_u.write.permissions;
1797c478bd9Sstevel@tonic-gate 		break;
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 	dacep->who.utf8string_val =
182ed57cab9Srg 	    kmem_alloc(sacep->who.utf8string_len, KM_SLEEP);
1837c478bd9Sstevel@tonic-gate 	bcopy(sacep->who.utf8string_val, dacep->who.utf8string_val,
1847c478bd9Sstevel@tonic-gate 	    sacep->who.utf8string_len);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate static void
deep_open_free(OPEN4res * res)1887c478bd9Sstevel@tonic-gate deep_open_free(OPEN4res *res)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	nfsace4 *acep;
1917c478bd9Sstevel@tonic-gate 	if (res->status != NFS4_OK)
1927c478bd9Sstevel@tonic-gate 		return;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	switch (res->delegation.delegation_type) {
1957c478bd9Sstevel@tonic-gate 	case OPEN_DELEGATE_NONE:
1967c478bd9Sstevel@tonic-gate 		return;
1977c478bd9Sstevel@tonic-gate 	case OPEN_DELEGATE_READ:
1987c478bd9Sstevel@tonic-gate 		acep = &res->delegation.open_delegation4_u.read.permissions;
1997c478bd9Sstevel@tonic-gate 		break;
2007c478bd9Sstevel@tonic-gate 	case OPEN_DELEGATE_WRITE:
2017c478bd9Sstevel@tonic-gate 		acep = &res->delegation.open_delegation4_u.write.permissions;
2027c478bd9Sstevel@tonic-gate 		break;
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	if (acep->who.utf8string_val) {
2067c478bd9Sstevel@tonic-gate 		kmem_free(acep->who.utf8string_val, acep->who.utf8string_len);
2077c478bd9Sstevel@tonic-gate 		acep->who.utf8string_val = NULL;
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate void
rfs4_free_reply(nfs_resop4 * rp)2127c478bd9Sstevel@tonic-gate rfs4_free_reply(nfs_resop4 *rp)
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate 	switch (rp->resop) {
2157c478bd9Sstevel@tonic-gate 	case OP_LOCK:
2167c478bd9Sstevel@tonic-gate 		deep_lock_free(&rp->nfs_resop4_u.oplock);
2177c478bd9Sstevel@tonic-gate 		break;
2187c478bd9Sstevel@tonic-gate 	case OP_OPEN:
2197c478bd9Sstevel@tonic-gate 		deep_open_free(&rp->nfs_resop4_u.opopen);
2207c478bd9Sstevel@tonic-gate 	default:
2217c478bd9Sstevel@tonic-gate 		break;
2227c478bd9Sstevel@tonic-gate 	}
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate void
rfs4_copy_reply(nfs_resop4 * dst,nfs_resop4 * src)2267c478bd9Sstevel@tonic-gate rfs4_copy_reply(nfs_resop4 *dst, nfs_resop4 *src)
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	*dst = *src;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/* Handle responses that need deep copy */
2317c478bd9Sstevel@tonic-gate 	switch (src->resop) {
2327c478bd9Sstevel@tonic-gate 	case OP_LOCK:
2337c478bd9Sstevel@tonic-gate 		deep_lock_copy(&dst->nfs_resop4_u.oplock,
234ed57cab9Srg 		    &src->nfs_resop4_u.oplock);
2357c478bd9Sstevel@tonic-gate 		break;
2367c478bd9Sstevel@tonic-gate 	case OP_OPEN:
2377c478bd9Sstevel@tonic-gate 		deep_open_copy(&dst->nfs_resop4_u.opopen,
238ed57cab9Srg 		    &src->nfs_resop4_u.opopen);
2397c478bd9Sstevel@tonic-gate 		break;
2407c478bd9Sstevel@tonic-gate 	default:
2417c478bd9Sstevel@tonic-gate 		break;
2427c478bd9Sstevel@tonic-gate 	};
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate  * This is the implementation of the underlying state engine. The
2477c478bd9Sstevel@tonic-gate  * public interface to this engine is described by
2487c478bd9Sstevel@tonic-gate  * nfs4_state.h. Callers to the engine should hold no state engine
2497c478bd9Sstevel@tonic-gate  * locks when they call in to it. If the protocol needs to lock data
2507c478bd9Sstevel@tonic-gate  * structures it should do so after acquiring all references to them
2517c478bd9Sstevel@tonic-gate  * first and then follow the following lock order:
2527c478bd9Sstevel@tonic-gate  *
2537c478bd9Sstevel@tonic-gate  *	client > openowner > state > lo_state > lockowner > file.
2547c478bd9Sstevel@tonic-gate  *
2557c478bd9Sstevel@tonic-gate  * Internally we only allow a thread to hold one hash bucket lock at a
2567c478bd9Sstevel@tonic-gate  * time and the lock is higher in the lock order (must be acquired
2577c478bd9Sstevel@tonic-gate  * first) than the data structure that is on that hash list.
2587c478bd9Sstevel@tonic-gate  *
2597c478bd9Sstevel@tonic-gate  * If a new reference was acquired by the caller, that reference needs
2607c478bd9Sstevel@tonic-gate  * to be released after releasing all acquired locks with the
2617c478bd9Sstevel@tonic-gate  * corresponding rfs4_*_rele routine.
2627c478bd9Sstevel@tonic-gate  */
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * This code is some what prototypical for now. Its purpose currently is to
2667c478bd9Sstevel@tonic-gate  * implement the interfaces sufficiently to finish the higher protocol
2677c478bd9Sstevel@tonic-gate  * elements. This will be replaced by a dynamically resizeable tables
2687c478bd9Sstevel@tonic-gate  * backed by kmem_cache allocator. However synchronization is handled
2697c478bd9Sstevel@tonic-gate  * correctly (I hope) and will not change by much.  The mutexes for
2707c478bd9Sstevel@tonic-gate  * the hash buckets that can be used to create new instances of data
2717c478bd9Sstevel@tonic-gate  * structures  might be good candidates to evolve into reader writer
2727c478bd9Sstevel@tonic-gate  * locks. If it has to do a creation, it would be holding the
2737c478bd9Sstevel@tonic-gate  * mutex across a kmem_alloc with KM_SLEEP specified.
2747c478bd9Sstevel@tonic-gate  */
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate #ifdef DEBUG
2777c478bd9Sstevel@tonic-gate #define	TABSIZE 17
2787c478bd9Sstevel@tonic-gate #else
2797c478bd9Sstevel@tonic-gate #define	TABSIZE 2047
2807c478bd9Sstevel@tonic-gate #endif
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate #define	ADDRHASH(key) ((unsigned long)(key) >> 3)
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate #define	MAXTABSZ 1024*1024
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate /* The values below are rfs4_lease_time units */
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate #ifdef DEBUG
2897c478bd9Sstevel@tonic-gate #define	CLIENT_CACHE_TIME 1
2907c478bd9Sstevel@tonic-gate #define	OPENOWNER_CACHE_TIME 1
2917c478bd9Sstevel@tonic-gate #define	STATE_CACHE_TIME 1
2927c478bd9Sstevel@tonic-gate #define	LO_STATE_CACHE_TIME 1
2937c478bd9Sstevel@tonic-gate #define	LOCKOWNER_CACHE_TIME 1
2947c478bd9Sstevel@tonic-gate #define	FILE_CACHE_TIME 3
2957c478bd9Sstevel@tonic-gate #define	DELEG_STATE_CACHE_TIME 1
2967c478bd9Sstevel@tonic-gate #else
2977c478bd9Sstevel@tonic-gate #define	CLIENT_CACHE_TIME 10
2987c478bd9Sstevel@tonic-gate #define	OPENOWNER_CACHE_TIME 5
2997c478bd9Sstevel@tonic-gate #define	STATE_CACHE_TIME 1
3007c478bd9Sstevel@tonic-gate #define	LO_STATE_CACHE_TIME 1
3017c478bd9Sstevel@tonic-gate #define	LOCKOWNER_CACHE_TIME 3
3027c478bd9Sstevel@tonic-gate #define	FILE_CACHE_TIME 40
3037c478bd9Sstevel@tonic-gate #define	DELEG_STATE_CACHE_TIME 1
3047c478bd9Sstevel@tonic-gate #endif
3057c478bd9Sstevel@tonic-gate 
3060dfe541eSEvan Layton /*
3070dfe541eSEvan Layton  * NFSv4 server state databases
3080dfe541eSEvan Layton  *
3090dfe541eSEvan Layton  * Initilized when the module is loaded and used by NFSv4 state tables.
3100dfe541eSEvan Layton  * These kmem_cache databases are global, the tables that make use of these
3110dfe541eSEvan Layton  * are per zone.
3120dfe541eSEvan Layton  */
3130dfe541eSEvan Layton kmem_cache_t *rfs4_client_mem_cache;
3140dfe541eSEvan Layton kmem_cache_t *rfs4_clntIP_mem_cache;
3150dfe541eSEvan Layton kmem_cache_t *rfs4_openown_mem_cache;
3160dfe541eSEvan Layton kmem_cache_t *rfs4_openstID_mem_cache;
3170dfe541eSEvan Layton kmem_cache_t *rfs4_lockstID_mem_cache;
3180dfe541eSEvan Layton kmem_cache_t *rfs4_lockown_mem_cache;
3190dfe541eSEvan Layton kmem_cache_t *rfs4_file_mem_cache;
3200dfe541eSEvan Layton kmem_cache_t *rfs4_delegstID_mem_cache;
321*f44e1126SVitaliy Gusev kmem_cache_t *rfs4_session_mem_cache;
3227c478bd9Sstevel@tonic-gate 
3230dfe541eSEvan Layton /*
3240dfe541eSEvan Layton  * NFSv4 state table functions
3250dfe541eSEvan Layton  */
3267c478bd9Sstevel@tonic-gate static bool_t rfs4_client_create(rfs4_entry_t, void *);
327cee86682Scalum static void rfs4_dss_remove_cpleaf(rfs4_client_t *);
328cee86682Scalum static void rfs4_dss_remove_leaf(rfs4_servinst_t *, char *, char *);
3297c478bd9Sstevel@tonic-gate static void rfs4_client_destroy(rfs4_entry_t);
3307c478bd9Sstevel@tonic-gate static bool_t rfs4_client_expiry(rfs4_entry_t);
3317c478bd9Sstevel@tonic-gate static uint32_t clientid_hash(void *);
3327c478bd9Sstevel@tonic-gate static bool_t clientid_compare(rfs4_entry_t, void *);
3337c478bd9Sstevel@tonic-gate static void *clientid_mkkey(rfs4_entry_t);
3347c478bd9Sstevel@tonic-gate static uint32_t nfsclnt_hash(void *);
3357c478bd9Sstevel@tonic-gate static bool_t nfsclnt_compare(rfs4_entry_t, void *);
3367c478bd9Sstevel@tonic-gate static void *nfsclnt_mkkey(rfs4_entry_t);
3372f172c55SRobert Thurlow static bool_t rfs4_clntip_expiry(rfs4_entry_t);
3382f172c55SRobert Thurlow static void rfs4_clntip_destroy(rfs4_entry_t);
3392f172c55SRobert Thurlow static bool_t rfs4_clntip_create(rfs4_entry_t, void *);
3402f172c55SRobert Thurlow static uint32_t clntip_hash(void *);
3412f172c55SRobert Thurlow static bool_t clntip_compare(rfs4_entry_t, void *);
3422f172c55SRobert Thurlow static void *clntip_mkkey(rfs4_entry_t);
3437c478bd9Sstevel@tonic-gate static bool_t rfs4_openowner_create(rfs4_entry_t, void *);
3447c478bd9Sstevel@tonic-gate static void rfs4_openowner_destroy(rfs4_entry_t);
3457c478bd9Sstevel@tonic-gate static bool_t rfs4_openowner_expiry(rfs4_entry_t);
3467c478bd9Sstevel@tonic-gate static uint32_t openowner_hash(void *);
3477c478bd9Sstevel@tonic-gate static bool_t openowner_compare(rfs4_entry_t, void *);
3487c478bd9Sstevel@tonic-gate static void *openowner_mkkey(rfs4_entry_t);
3497c478bd9Sstevel@tonic-gate static bool_t rfs4_state_create(rfs4_entry_t, void *);
3507c478bd9Sstevel@tonic-gate static void rfs4_state_destroy(rfs4_entry_t);
3517c478bd9Sstevel@tonic-gate static bool_t rfs4_state_expiry(rfs4_entry_t);
3527c478bd9Sstevel@tonic-gate static uint32_t state_hash(void *);
3537c478bd9Sstevel@tonic-gate static bool_t state_compare(rfs4_entry_t, void *);
3547c478bd9Sstevel@tonic-gate static void *state_mkkey(rfs4_entry_t);
3557c478bd9Sstevel@tonic-gate static uint32_t state_owner_file_hash(void *);
3567c478bd9Sstevel@tonic-gate static bool_t state_owner_file_compare(rfs4_entry_t, void *);
3577c478bd9Sstevel@tonic-gate static void *state_owner_file_mkkey(rfs4_entry_t);
3587c478bd9Sstevel@tonic-gate static uint32_t state_file_hash(void *);
3597c478bd9Sstevel@tonic-gate static bool_t state_file_compare(rfs4_entry_t, void *);
3607c478bd9Sstevel@tonic-gate static void *state_file_mkkey(rfs4_entry_t);
3617c478bd9Sstevel@tonic-gate static bool_t rfs4_lo_state_create(rfs4_entry_t, void *);
3627c478bd9Sstevel@tonic-gate static void rfs4_lo_state_destroy(rfs4_entry_t);
3637c478bd9Sstevel@tonic-gate static bool_t rfs4_lo_state_expiry(rfs4_entry_t);
3647c478bd9Sstevel@tonic-gate static uint32_t lo_state_hash(void *);
3657c478bd9Sstevel@tonic-gate static bool_t lo_state_compare(rfs4_entry_t, void *);
3667c478bd9Sstevel@tonic-gate static void *lo_state_mkkey(rfs4_entry_t);
3677c478bd9Sstevel@tonic-gate static uint32_t lo_state_lo_hash(void *);
3687c478bd9Sstevel@tonic-gate static bool_t lo_state_lo_compare(rfs4_entry_t, void *);
3697c478bd9Sstevel@tonic-gate static void *lo_state_lo_mkkey(rfs4_entry_t);
3707c478bd9Sstevel@tonic-gate static bool_t rfs4_lockowner_create(rfs4_entry_t, void *);
3717c478bd9Sstevel@tonic-gate static void rfs4_lockowner_destroy(rfs4_entry_t);
3727c478bd9Sstevel@tonic-gate static bool_t rfs4_lockowner_expiry(rfs4_entry_t);
3737c478bd9Sstevel@tonic-gate static uint32_t lockowner_hash(void *);
3747c478bd9Sstevel@tonic-gate static bool_t lockowner_compare(rfs4_entry_t, void *);
3757c478bd9Sstevel@tonic-gate static void *lockowner_mkkey(rfs4_entry_t);
3767c478bd9Sstevel@tonic-gate static uint32_t pid_hash(void *);
3777c478bd9Sstevel@tonic-gate static bool_t pid_compare(rfs4_entry_t, void *);
3787c478bd9Sstevel@tonic-gate static void *pid_mkkey(rfs4_entry_t);
3797c478bd9Sstevel@tonic-gate static bool_t rfs4_file_create(rfs4_entry_t, void *);
3807c478bd9Sstevel@tonic-gate static void rfs4_file_destroy(rfs4_entry_t);
3817c478bd9Sstevel@tonic-gate static uint32_t file_hash(void *);
3827c478bd9Sstevel@tonic-gate static bool_t file_compare(rfs4_entry_t, void *);
3837c478bd9Sstevel@tonic-gate static void *file_mkkey(rfs4_entry_t);
3847c478bd9Sstevel@tonic-gate static bool_t rfs4_deleg_state_create(rfs4_entry_t, void *);
3857c478bd9Sstevel@tonic-gate static void rfs4_deleg_state_destroy(rfs4_entry_t);
3867c478bd9Sstevel@tonic-gate static bool_t rfs4_deleg_state_expiry(rfs4_entry_t);
3877c478bd9Sstevel@tonic-gate static uint32_t deleg_hash(void *);
3887c478bd9Sstevel@tonic-gate static bool_t deleg_compare(rfs4_entry_t, void *);
3897c478bd9Sstevel@tonic-gate static void *deleg_mkkey(rfs4_entry_t);
3907c478bd9Sstevel@tonic-gate static uint32_t deleg_state_hash(void *);
3917c478bd9Sstevel@tonic-gate static bool_t deleg_state_compare(rfs4_entry_t, void *);
3927c478bd9Sstevel@tonic-gate static void *deleg_state_mkkey(rfs4_entry_t);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate static void rfs4_state_rele_nounlock(rfs4_state_t *);
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate static int rfs4_ss_enabled = 0;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate void
rfs4_ss_pnfree(rfs4_ss_pn_t * ss_pn)3997c478bd9Sstevel@tonic-gate rfs4_ss_pnfree(rfs4_ss_pn_t *ss_pn)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	kmem_free(ss_pn, sizeof (rfs4_ss_pn_t));
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate static rfs4_ss_pn_t *
rfs4_ss_pnalloc(char * dir,char * leaf)4057c478bd9Sstevel@tonic-gate rfs4_ss_pnalloc(char *dir, char *leaf)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate 	rfs4_ss_pn_t *ss_pn;
4080dfe541eSEvan Layton 	int dir_len, leaf_len;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	/*
4117c478bd9Sstevel@tonic-gate 	 * validate we have a resonable path
4127c478bd9Sstevel@tonic-gate 	 * (account for the '/' and trailing null)
4137c478bd9Sstevel@tonic-gate 	 */
4147c478bd9Sstevel@tonic-gate 	if ((dir_len = strlen(dir)) > MAXPATHLEN ||
415ed57cab9Srg 	    (leaf_len = strlen(leaf)) > MAXNAMELEN ||
416ed57cab9Srg 	    (dir_len + leaf_len + 2) > MAXPATHLEN) {
4177c478bd9Sstevel@tonic-gate 		return (NULL);
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	ss_pn = kmem_alloc(sizeof (rfs4_ss_pn_t), KM_SLEEP);
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	(void) snprintf(ss_pn->pn, MAXPATHLEN, "%s/%s", dir, leaf);
4237c478bd9Sstevel@tonic-gate 	/* Handy pointer to just the leaf name */
4247c478bd9Sstevel@tonic-gate 	ss_pn->leaf = ss_pn->pn + dir_len + 1;
4257c478bd9Sstevel@tonic-gate 	return (ss_pn);
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate  * Move the "leaf" filename from "sdir" directory
4317c478bd9Sstevel@tonic-gate  * to the "ddir" directory. Return the pathname of
4327c478bd9Sstevel@tonic-gate  * the destination unless the rename fails in which
4337c478bd9Sstevel@tonic-gate  * case we need to return the source pathname.
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate static rfs4_ss_pn_t *
rfs4_ss_movestate(char * sdir,char * ddir,char * leaf)4367c478bd9Sstevel@tonic-gate rfs4_ss_movestate(char *sdir, char *ddir, char *leaf)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 	rfs4_ss_pn_t *src, *dst;
4397c478bd9Sstevel@tonic-gate 
440cee86682Scalum 	if ((src = rfs4_ss_pnalloc(sdir, leaf)) == NULL)
4417c478bd9Sstevel@tonic-gate 		return (NULL);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	if ((dst = rfs4_ss_pnalloc(ddir, leaf)) == NULL) {
4447c478bd9Sstevel@tonic-gate 		rfs4_ss_pnfree(src);
4457c478bd9Sstevel@tonic-gate 		return (NULL);
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/*
4497c478bd9Sstevel@tonic-gate 	 * If the rename fails we shall return the src
4507c478bd9Sstevel@tonic-gate 	 * pathname and free the dst. Otherwise we need
4517c478bd9Sstevel@tonic-gate 	 * to free the src and return the dst pathanme.
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	if (vn_rename(src->pn, dst->pn, UIO_SYSSPACE)) {
4547c478bd9Sstevel@tonic-gate 		rfs4_ss_pnfree(dst);
4557c478bd9Sstevel@tonic-gate 		return (src);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 	rfs4_ss_pnfree(src);
4587c478bd9Sstevel@tonic-gate 	return (dst);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate static rfs4_oldstate_t *
rfs4_ss_getstate(vnode_t * dvp,rfs4_ss_pn_t * ss_pn)4637c478bd9Sstevel@tonic-gate rfs4_ss_getstate(vnode_t *dvp, rfs4_ss_pn_t *ss_pn)
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate 	struct uio uio;
4667c478bd9Sstevel@tonic-gate 	struct iovec iov[3];
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	rfs4_oldstate_t *cl_ss = NULL;
4697c478bd9Sstevel@tonic-gate 	vnode_t *vp;
4707c478bd9Sstevel@tonic-gate 	vattr_t va;
4717c478bd9Sstevel@tonic-gate 	uint_t id_len;
4727c478bd9Sstevel@tonic-gate 	int err, kill_file, file_vers;
4737c478bd9Sstevel@tonic-gate 
474cee86682Scalum 	if (ss_pn == NULL)
4757c478bd9Sstevel@tonic-gate 		return (NULL);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	/*
4787c478bd9Sstevel@tonic-gate 	 * open the state file.
4797c478bd9Sstevel@tonic-gate 	 */
4807c478bd9Sstevel@tonic-gate 	if (vn_open(ss_pn->pn, UIO_SYSSPACE, FREAD, 0, &vp, 0, 0) != 0) {
4817c478bd9Sstevel@tonic-gate 		return (NULL);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (vp->v_type != VREG) {
485da6c28aaSamw 		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
4867c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
4877c478bd9Sstevel@tonic-gate 		return (NULL);
4887c478bd9Sstevel@tonic-gate 	}
4897c478bd9Sstevel@tonic-gate 
490da6c28aaSamw 	err = VOP_ACCESS(vp, VREAD, 0, CRED(), NULL);
4917c478bd9Sstevel@tonic-gate 	if (err) {
4927c478bd9Sstevel@tonic-gate 		/*
4937c478bd9Sstevel@tonic-gate 		 * We don't have read access? better get the heck out.
4947c478bd9Sstevel@tonic-gate 		 */
495da6c28aaSamw 		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
4967c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
4977c478bd9Sstevel@tonic-gate 		return (NULL);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
5017c478bd9Sstevel@tonic-gate 	/*
5027c478bd9Sstevel@tonic-gate 	 * get the file size to do some basic validation
5037c478bd9Sstevel@tonic-gate 	 */
5047c478bd9Sstevel@tonic-gate 	va.va_mask = AT_SIZE;
505da6c28aaSamw 	err = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	kill_file = (va.va_size == 0 || va.va_size <
508ed57cab9Srg 	    (NFS4_VERIFIER_SIZE + sizeof (uint_t)+1));
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	if (err || kill_file) {
5117c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
512da6c28aaSamw 		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
5137c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
5147c478bd9Sstevel@tonic-gate 		if (kill_file) {
515da6c28aaSamw 			(void) VOP_REMOVE(dvp, ss_pn->leaf, CRED(), NULL, 0);
5167c478bd9Sstevel@tonic-gate 		}
5177c478bd9Sstevel@tonic-gate 		return (NULL);
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	cl_ss = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP);
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	/*
5237c478bd9Sstevel@tonic-gate 	 * build iovecs to read in the file_version, verifier and id_len
5247c478bd9Sstevel@tonic-gate 	 */
5257c478bd9Sstevel@tonic-gate 	iov[0].iov_base = (caddr_t)&file_vers;
5267c478bd9Sstevel@tonic-gate 	iov[0].iov_len = sizeof (int);
527cee86682Scalum 	iov[1].iov_base = (caddr_t)&cl_ss->cl_id4.verifier;
5287c478bd9Sstevel@tonic-gate 	iov[1].iov_len = NFS4_VERIFIER_SIZE;
5297c478bd9Sstevel@tonic-gate 	iov[2].iov_base = (caddr_t)&id_len;
5307c478bd9Sstevel@tonic-gate 	iov[2].iov_len = sizeof (uint_t);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	uio.uio_iov = iov;
5337c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 3;
5347c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
5357c478bd9Sstevel@tonic-gate 	uio.uio_loffset = 0;
5367c478bd9Sstevel@tonic-gate 	uio.uio_resid = sizeof (int) + NFS4_VERIFIER_SIZE + sizeof (uint_t);
5377c478bd9Sstevel@tonic-gate 
538bd3561fbSToomas Soome 	err = VOP_READ(vp, &uio, FREAD, CRED(), NULL);
539bd3561fbSToomas Soome 	if (err != 0) {
5407c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
541da6c28aaSamw 		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
5427c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
5437c478bd9Sstevel@tonic-gate 		kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
5447c478bd9Sstevel@tonic-gate 		return (NULL);
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	/*
5487c478bd9Sstevel@tonic-gate 	 * if the file_version doesn't match or if the
5497c478bd9Sstevel@tonic-gate 	 * id_len is zero or the combination of the verifier,
5507c478bd9Sstevel@tonic-gate 	 * id_len and id_val is bigger than the file we have
5517c478bd9Sstevel@tonic-gate 	 * a problem. If so ditch the file.
5527c478bd9Sstevel@tonic-gate 	 */
5537c478bd9Sstevel@tonic-gate 	kill_file = (file_vers != NFS4_SS_VERSION || id_len == 0 ||
5547c478bd9Sstevel@tonic-gate 	    (id_len + NFS4_VERIFIER_SIZE + sizeof (uint_t)) > va.va_size);
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (err || kill_file) {
5577c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
558da6c28aaSamw 		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
5597c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
5607c478bd9Sstevel@tonic-gate 		kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
5617c478bd9Sstevel@tonic-gate 		if (kill_file) {
562da6c28aaSamw 			(void) VOP_REMOVE(dvp, ss_pn->leaf, CRED(), NULL, 0);
5637c478bd9Sstevel@tonic-gate 		}
5647c478bd9Sstevel@tonic-gate 		return (NULL);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	/*
5687c478bd9Sstevel@tonic-gate 	 * now get the client id value
5697c478bd9Sstevel@tonic-gate 	 */
5707c478bd9Sstevel@tonic-gate 	cl_ss->cl_id4.id_val = kmem_alloc(id_len, KM_SLEEP);
5717c478bd9Sstevel@tonic-gate 	iov[0].iov_base = cl_ss->cl_id4.id_val;
5727c478bd9Sstevel@tonic-gate 	iov[0].iov_len = id_len;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	uio.uio_iov = iov;
5757c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 1;
5767c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
5777c478bd9Sstevel@tonic-gate 	uio.uio_resid = cl_ss->cl_id4.id_len = id_len;
5787c478bd9Sstevel@tonic-gate 
579bd3561fbSToomas Soome 	err = VOP_READ(vp, &uio, FREAD, CRED(), NULL);
580bd3561fbSToomas Soome 	if (err != 0) {
5817c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
582da6c28aaSamw 		(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
5837c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
5847c478bd9Sstevel@tonic-gate 		kmem_free(cl_ss->cl_id4.id_val, id_len);
5857c478bd9Sstevel@tonic-gate 		kmem_free(cl_ss, sizeof (rfs4_oldstate_t));
5867c478bd9Sstevel@tonic-gate 		return (NULL);
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
590da6c28aaSamw 	(void) VOP_CLOSE(vp, FREAD, 1, (offset_t)0, CRED(), NULL);
5917c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
5927c478bd9Sstevel@tonic-gate 	return (cl_ss);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate #ifdef	nextdp
5967c478bd9Sstevel@tonic-gate #undef nextdp
5977c478bd9Sstevel@tonic-gate #endif
5987c478bd9Sstevel@tonic-gate #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
5997c478bd9Sstevel@tonic-gate 
600*f44e1126SVitaliy Gusev /*
601*f44e1126SVitaliy Gusev  * Check whether list already contains the client
602*f44e1126SVitaliy Gusev  * This protects against counting the same client twice.
603*f44e1126SVitaliy Gusev  */
604*f44e1126SVitaliy Gusev static bool_t
rfs4_ss_has_client(rfs4_oldstate_t * head,nfs_client_id4 * client)605*f44e1126SVitaliy Gusev rfs4_ss_has_client(rfs4_oldstate_t *head, nfs_client_id4 *client)
606*f44e1126SVitaliy Gusev {
607*f44e1126SVitaliy Gusev 	rfs4_oldstate_t *p;
608*f44e1126SVitaliy Gusev 
609*f44e1126SVitaliy Gusev 	for (p = head->next; p != head; p = p->next) {
610*f44e1126SVitaliy Gusev 		nfs_client_id4 *m = &p->cl_id4;
611*f44e1126SVitaliy Gusev 
612*f44e1126SVitaliy Gusev 		if (m->id_len != client->id_len)
613*f44e1126SVitaliy Gusev 			continue;
614*f44e1126SVitaliy Gusev 
615*f44e1126SVitaliy Gusev 		if (bcmp(m->id_val, client->id_val, client->id_len) == 0)
616*f44e1126SVitaliy Gusev 			continue;
617*f44e1126SVitaliy Gusev 
618*f44e1126SVitaliy Gusev 		/* client ids match */
619*f44e1126SVitaliy Gusev 		return (TRUE);
620*f44e1126SVitaliy Gusev 	}
621*f44e1126SVitaliy Gusev 
622*f44e1126SVitaliy Gusev 	return (FALSE);
623*f44e1126SVitaliy Gusev }
624*f44e1126SVitaliy Gusev 
6257c478bd9Sstevel@tonic-gate /*
626cee86682Scalum  * Add entries from statedir to supplied oldstate list.
627cee86682Scalum  * Optionally, move all entries from statedir -> destdir.
6287c478bd9Sstevel@tonic-gate  */
629*f44e1126SVitaliy Gusev static void
rfs4_ss_oldstate(rfs4_oldstate_t * oldstate,char * statedir,char * destdir)630cee86682Scalum rfs4_ss_oldstate(rfs4_oldstate_t *oldstate, char *statedir, char *destdir)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate 	rfs4_ss_pn_t *ss_pn;
6337c478bd9Sstevel@tonic-gate 	rfs4_oldstate_t *cl_ss = NULL;
6347c478bd9Sstevel@tonic-gate 	char	*dirt = NULL;
6357c478bd9Sstevel@tonic-gate 	int	err, dir_eof = 0, size = 0;
6367c478bd9Sstevel@tonic-gate 	vnode_t *dvp;
6377c478bd9Sstevel@tonic-gate 	struct iovec iov;
6387c478bd9Sstevel@tonic-gate 	struct uio uio;
6397c478bd9Sstevel@tonic-gate 	struct dirent64 *dep;
6407c478bd9Sstevel@tonic-gate 	offset_t dirchunk_offset = 0;
641*f44e1126SVitaliy Gusev 	unsigned int nclients = 0;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	/*
6447c478bd9Sstevel@tonic-gate 	 * open the state directory
6457c478bd9Sstevel@tonic-gate 	 */
646cee86682Scalum 	if (vn_open(statedir, UIO_SYSSPACE, FREAD, 0, &dvp, 0, 0))
6477c478bd9Sstevel@tonic-gate 		return;
6487c478bd9Sstevel@tonic-gate 
649da6c28aaSamw 	if (dvp->v_type != VDIR || VOP_ACCESS(dvp, VREAD, 0, CRED(), NULL))
6507c478bd9Sstevel@tonic-gate 		goto out;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	dirt = kmem_alloc(RFS4_SS_DIRSIZE, KM_SLEEP);
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	/*
6557c478bd9Sstevel@tonic-gate 	 * Get and process the directory entries
6567c478bd9Sstevel@tonic-gate 	 */
6577c478bd9Sstevel@tonic-gate 	while (!dir_eof) {
6587c478bd9Sstevel@tonic-gate 		(void) VOP_RWLOCK(dvp, V_WRITELOCK_FALSE, NULL);
6597c478bd9Sstevel@tonic-gate 		iov.iov_base = dirt;
6607c478bd9Sstevel@tonic-gate 		iov.iov_len = RFS4_SS_DIRSIZE;
6617c478bd9Sstevel@tonic-gate 		uio.uio_iov = &iov;
6627c478bd9Sstevel@tonic-gate 		uio.uio_iovcnt = 1;
6637c478bd9Sstevel@tonic-gate 		uio.uio_segflg = UIO_SYSSPACE;
6647c478bd9Sstevel@tonic-gate 		uio.uio_loffset = dirchunk_offset;
6657c478bd9Sstevel@tonic-gate 		uio.uio_resid = RFS4_SS_DIRSIZE;
6667c478bd9Sstevel@tonic-gate 
667da6c28aaSamw 		err = VOP_READDIR(dvp, &uio, CRED(), &dir_eof, NULL, 0);
6687c478bd9Sstevel@tonic-gate 		VOP_RWUNLOCK(dvp, V_WRITELOCK_FALSE, NULL);
669cee86682Scalum 		if (err)
6707c478bd9Sstevel@tonic-gate 			goto out;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 		size = RFS4_SS_DIRSIZE - uio.uio_resid;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 		/*
6757c478bd9Sstevel@tonic-gate 		 * Process all the directory entries in this
6767c478bd9Sstevel@tonic-gate 		 * readdir chunk
6777c478bd9Sstevel@tonic-gate 		 */
6787c478bd9Sstevel@tonic-gate 		for (dep = (struct dirent64 *)dirt; size > 0;
679ed57cab9Srg 		    dep = nextdp(dep)) {
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 			size -= dep->d_reclen;
6827c478bd9Sstevel@tonic-gate 			dirchunk_offset = dep->d_off;
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 			/*
6857c478bd9Sstevel@tonic-gate 			 * Skip '.' and '..'
6867c478bd9Sstevel@tonic-gate 			 */
687cee86682Scalum 			if (NFS_IS_DOTNAME(dep->d_name))
6887c478bd9Sstevel@tonic-gate 				continue;
6897c478bd9Sstevel@tonic-gate 
690cee86682Scalum 			ss_pn = rfs4_ss_pnalloc(statedir, dep->d_name);
691cee86682Scalum 			if (ss_pn == NULL)
6927c478bd9Sstevel@tonic-gate 				continue;
6937c478bd9Sstevel@tonic-gate 
694bd3561fbSToomas Soome 			cl_ss = rfs4_ss_getstate(dvp, ss_pn);
695bd3561fbSToomas Soome 			if (cl_ss != NULL) {
696cee86682Scalum 				if (destdir != NULL) {
6977c478bd9Sstevel@tonic-gate 					rfs4_ss_pnfree(ss_pn);
6987c478bd9Sstevel@tonic-gate 					cl_ss->ss_pn = rfs4_ss_movestate(
699ed57cab9Srg 					    statedir, destdir, dep->d_name);
7007c478bd9Sstevel@tonic-gate 				} else {
7017c478bd9Sstevel@tonic-gate 					cl_ss->ss_pn = ss_pn;
7027c478bd9Sstevel@tonic-gate 				}
703*f44e1126SVitaliy Gusev 
704*f44e1126SVitaliy Gusev 				if (!rfs4_ss_has_client(oldstate,
705*f44e1126SVitaliy Gusev 				    &cl_ss->cl_id4))
706*f44e1126SVitaliy Gusev 					nclients++;
707*f44e1126SVitaliy Gusev 
708cee86682Scalum 				insque(cl_ss, oldstate);
7097c478bd9Sstevel@tonic-gate 			} else {
7107c478bd9Sstevel@tonic-gate 				rfs4_ss_pnfree(ss_pn);
7117c478bd9Sstevel@tonic-gate 			}
7127c478bd9Sstevel@tonic-gate 		}
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
715cee86682Scalum out:
716da6c28aaSamw 	(void) VOP_CLOSE(dvp, FREAD, 1, (offset_t)0, CRED(), NULL);
7177c478bd9Sstevel@tonic-gate 	VN_RELE(dvp);
7187c478bd9Sstevel@tonic-gate 	if (dirt)
7197c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)dirt, RFS4_SS_DIRSIZE);
720*f44e1126SVitaliy Gusev 
721*f44e1126SVitaliy Gusev 	if (nclients > 0) {
722*f44e1126SVitaliy Gusev 		nfs4_srv_t *nsrv4 = nfs4_get_srv();
723*f44e1126SVitaliy Gusev 
724*f44e1126SVitaliy Gusev 		atomic_add_32(&(nsrv4->nfs4_cur_servinst->nreclaim), nclients);
725*f44e1126SVitaliy Gusev 	}
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
728cee86682Scalum static void
rfs4_ss_init(nfs4_srv_t * nsrv4)7290dfe541eSEvan Layton rfs4_ss_init(nfs4_srv_t *nsrv4)
7307c478bd9Sstevel@tonic-gate {
731cee86682Scalum 	int npaths = 1;
732cee86682Scalum 	char *default_dss_path = NFS4_DSS_VAR_DIR;
7337c478bd9Sstevel@tonic-gate 
734cee86682Scalum 	/* read the default stable storage state */
7350dfe541eSEvan Layton 	rfs4_dss_readstate(nsrv4, npaths, &default_dss_path);
736cee86682Scalum 
737cee86682Scalum 	rfs4_ss_enabled = 1;
738cee86682Scalum }
739cee86682Scalum 
740cee86682Scalum static void
rfs4_ss_fini(nfs4_srv_t * nsrv4)7410dfe541eSEvan Layton rfs4_ss_fini(nfs4_srv_t *nsrv4)
742cee86682Scalum {
743cee86682Scalum 	rfs4_servinst_t *sip;
744cee86682Scalum 
7450dfe541eSEvan Layton 	mutex_enter(&nsrv4->servinst_lock);
7460dfe541eSEvan Layton 	sip = nsrv4->nfs4_cur_servinst;
747cee86682Scalum 	while (sip != NULL) {
748cee86682Scalum 		rfs4_dss_clear_oldstate(sip);
749cee86682Scalum 		sip = sip->next;
7507c478bd9Sstevel@tonic-gate 	}
7510dfe541eSEvan Layton 	mutex_exit(&nsrv4->servinst_lock);
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate /*
755cee86682Scalum  * Remove all oldstate files referenced by this servinst.
7567c478bd9Sstevel@tonic-gate  */
7577c478bd9Sstevel@tonic-gate static void
rfs4_dss_clear_oldstate(rfs4_servinst_t * sip)758cee86682Scalum rfs4_dss_clear_oldstate(rfs4_servinst_t *sip)
7597c478bd9Sstevel@tonic-gate {
760cee86682Scalum 	rfs4_oldstate_t *os_head, *osp;
761cee86682Scalum 
762cee86682Scalum 	rw_enter(&sip->oldstate_lock, RW_WRITER);
763cee86682Scalum 	os_head = sip->oldstate;
7647c478bd9Sstevel@tonic-gate 
765eec118a1SMarcel Telka 	if (os_head == NULL) {
766eec118a1SMarcel Telka 		rw_exit(&sip->oldstate_lock);
7677c478bd9Sstevel@tonic-gate 		return;
768eec118a1SMarcel Telka 	}
7697c478bd9Sstevel@tonic-gate 
770cee86682Scalum 	/* skip dummy entry */
771cee86682Scalum 	osp = os_head->next;
772cee86682Scalum 	while (osp != os_head) {
773cee86682Scalum 		char *leaf = osp->ss_pn->leaf;
774cee86682Scalum 		rfs4_oldstate_t *os_next;
7757c478bd9Sstevel@tonic-gate 
776cee86682Scalum 		rfs4_dss_remove_leaf(sip, NFS4_DSS_OLDSTATE_LEAF, leaf);
7777c478bd9Sstevel@tonic-gate 
778cee86682Scalum 		if (osp->cl_id4.id_val)
779cee86682Scalum 			kmem_free(osp->cl_id4.id_val, osp->cl_id4.id_len);
780eec118a1SMarcel Telka 		rfs4_ss_pnfree(osp->ss_pn);
7817c478bd9Sstevel@tonic-gate 
782cee86682Scalum 		os_next = osp->next;
783cee86682Scalum 		remque(osp);
784cee86682Scalum 		kmem_free(osp, sizeof (rfs4_oldstate_t));
785cee86682Scalum 		osp = os_next;
786cee86682Scalum 	}
787cee86682Scalum 
788cee86682Scalum 	rw_exit(&sip->oldstate_lock);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
791cee86682Scalum /*
792cee86682Scalum  * Form the state and oldstate paths, and read in the stable storage files.
793cee86682Scalum  */
794cee86682Scalum void
rfs4_dss_readstate(nfs4_srv_t * nsrv4,int npaths,char ** paths)7950dfe541eSEvan Layton rfs4_dss_readstate(nfs4_srv_t *nsrv4, int npaths, char **paths)
7967c478bd9Sstevel@tonic-gate {
797cee86682Scalum 	int i;
798cee86682Scalum 	char *state, *oldstate;
7997c478bd9Sstevel@tonic-gate 
800cee86682Scalum 	state = kmem_alloc(MAXPATHLEN, KM_SLEEP);
801cee86682Scalum 	oldstate = kmem_alloc(MAXPATHLEN, KM_SLEEP);
8027c478bd9Sstevel@tonic-gate 
803cee86682Scalum 	for (i = 0; i < npaths; i++) {
804cee86682Scalum 		char *path = paths[i];
8057c478bd9Sstevel@tonic-gate 
806cee86682Scalum 		(void) sprintf(state, "%s/%s", path, NFS4_DSS_STATE_LEAF);
807cee86682Scalum 		(void) sprintf(oldstate, "%s/%s", path, NFS4_DSS_OLDSTATE_LEAF);
8087c478bd9Sstevel@tonic-gate 
809cee86682Scalum 		/*
810cee86682Scalum 		 * Populate the current server instance's oldstate list.
811cee86682Scalum 		 *
812cee86682Scalum 		 * 1. Read stable storage data from old state directory,
813cee86682Scalum 		 *    leaving its contents alone.
814cee86682Scalum 		 *
815cee86682Scalum 		 * 2. Read stable storage data from state directory,
816cee86682Scalum 		 *    and move the latter's contents to old state
817cee86682Scalum 		 *    directory.
818cee86682Scalum 		 */
819*f44e1126SVitaliy Gusev 		rfs4_ss_oldstate(nsrv4->nfs4_cur_servinst->oldstate,
820*f44e1126SVitaliy Gusev 		    oldstate, NULL);
821*f44e1126SVitaliy Gusev 		rfs4_ss_oldstate(nsrv4->nfs4_cur_servinst->oldstate,
822*f44e1126SVitaliy Gusev 		    state, oldstate);
8237c478bd9Sstevel@tonic-gate 	}
824cee86682Scalum 
825cee86682Scalum 	kmem_free(state, MAXPATHLEN);
826cee86682Scalum 	kmem_free(oldstate, MAXPATHLEN);
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate /*
8317c478bd9Sstevel@tonic-gate  * Check if we are still in grace and if the client can be
8327c478bd9Sstevel@tonic-gate  * granted permission to perform reclaims.
8337c478bd9Sstevel@tonic-gate  */
8347c478bd9Sstevel@tonic-gate void
rfs4_ss_chkclid(nfs4_srv_t * nsrv4,rfs4_client_t * cp)8350dfe541eSEvan Layton rfs4_ss_chkclid(nfs4_srv_t *nsrv4, rfs4_client_t *cp)
8367c478bd9Sstevel@tonic-gate {
837cee86682Scalum 	rfs4_servinst_t *sip;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/*
840cee86682Scalum 	 * It should be sufficient to check the oldstate data for just
841cee86682Scalum 	 * this client's instance. However, since our per-instance
842cee86682Scalum 	 * client grouping is solely temporal, HA-NFSv4 RG failover
843cee86682Scalum 	 * might result in clients of the same RG being partitioned into
844cee86682Scalum 	 * separate instances.
845cee86682Scalum 	 *
846cee86682Scalum 	 * Until the client grouping is improved, we must check the
847cee86682Scalum 	 * oldstate data for all instances with an active grace period.
848cee86682Scalum 	 *
849cee86682Scalum 	 * This also serves as the mechanism to remove stale oldstate data.
850cee86682Scalum 	 * The first time we check an instance after its grace period has
851cee86682Scalum 	 * expired, the oldstate data should be cleared.
852cee86682Scalum 	 *
853cee86682Scalum 	 * Start at the current instance, and walk the list backwards
854cee86682Scalum 	 * to the first.
8557c478bd9Sstevel@tonic-gate 	 */
8560dfe541eSEvan Layton 	mutex_enter(&nsrv4->servinst_lock);
8570dfe541eSEvan Layton 	for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev) {
858cee86682Scalum 		rfs4_ss_chkclid_sip(cp, sip);
8597c478bd9Sstevel@tonic-gate 
860cee86682Scalum 		/* if the above check found this client, we're done */
861d216dff5SRobert Mastors 		if (cp->rc_can_reclaim)
862cee86682Scalum 			break;
863cee86682Scalum 	}
8640dfe541eSEvan Layton 	mutex_exit(&nsrv4->servinst_lock);
865cee86682Scalum }
8667c478bd9Sstevel@tonic-gate 
867cee86682Scalum static void
rfs4_ss_chkclid_sip(rfs4_client_t * cp,rfs4_servinst_t * sip)868cee86682Scalum rfs4_ss_chkclid_sip(rfs4_client_t *cp, rfs4_servinst_t *sip)
869cee86682Scalum {
870cee86682Scalum 	rfs4_oldstate_t *osp, *os_head;
8717c478bd9Sstevel@tonic-gate 
872cee86682Scalum 	/* short circuit everything if this server instance has no oldstate */
873cee86682Scalum 	rw_enter(&sip->oldstate_lock, RW_READER);
874cee86682Scalum 	os_head = sip->oldstate;
875cee86682Scalum 	rw_exit(&sip->oldstate_lock);
876cee86682Scalum 	if (os_head == NULL)
8777c478bd9Sstevel@tonic-gate 		return;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	/*
880cee86682Scalum 	 * If this server instance is no longer in a grace period then
881cee86682Scalum 	 * the client won't be able to reclaim. No further need for this
882cee86682Scalum 	 * instance's oldstate data, so it can be cleared.
8837c478bd9Sstevel@tonic-gate 	 */
884cee86682Scalum 	if (!rfs4_servinst_in_grace(sip))
885cee86682Scalum 		return;
8867c478bd9Sstevel@tonic-gate 
887cee86682Scalum 	/* this instance is still in grace; search for the clientid */
8887c478bd9Sstevel@tonic-gate 
889cee86682Scalum 	rw_enter(&sip->oldstate_lock, RW_READER);
890cee86682Scalum 
891cee86682Scalum 	os_head = sip->oldstate;
892cee86682Scalum 	/* skip dummy entry */
893cee86682Scalum 	osp = os_head->next;
8947c478bd9Sstevel@tonic-gate 	while (osp != os_head) {
895d216dff5SRobert Mastors 		if (osp->cl_id4.id_len == cp->rc_nfs_client.id_len) {
896d216dff5SRobert Mastors 			if (bcmp(osp->cl_id4.id_val, cp->rc_nfs_client.id_val,
897ed57cab9Srg 			    osp->cl_id4.id_len) == 0) {
898d216dff5SRobert Mastors 				cp->rc_can_reclaim = 1;
8997c478bd9Sstevel@tonic-gate 				break;
9007c478bd9Sstevel@tonic-gate 			}
9017c478bd9Sstevel@tonic-gate 		}
9027c478bd9Sstevel@tonic-gate 		osp = osp->next;
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 
905cee86682Scalum 	rw_exit(&sip->oldstate_lock);
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate /*
909cee86682Scalum  * Place client information into stable storage: 1/3.
910cee86682Scalum  * First, generate the leaf filename, from the client's IP address and
911cee86682Scalum  * the server-generated short-hand clientid.
9127c478bd9Sstevel@tonic-gate  */
9137c478bd9Sstevel@tonic-gate void
rfs4_ss_clid(nfs4_srv_t * nsrv4,rfs4_client_t * cp)9140dfe541eSEvan Layton rfs4_ss_clid(nfs4_srv_t *nsrv4, rfs4_client_t *cp)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate 	const char *kinet_ntop6(uchar_t *, char *, size_t);
9177c478bd9Sstevel@tonic-gate 	char leaf[MAXNAMELEN], buf[INET6_ADDRSTRLEN];
9187c478bd9Sstevel@tonic-gate 	struct sockaddr *ca;
9197c478bd9Sstevel@tonic-gate 	uchar_t *b;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	if (rfs4_ss_enabled == 0) {
9227c478bd9Sstevel@tonic-gate 		return;
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	buf[0] = 0;
9267c478bd9Sstevel@tonic-gate 
9272f172c55SRobert Thurlow 	ca = (struct sockaddr *)&cp->rc_addr;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	/*
9307c478bd9Sstevel@tonic-gate 	 * Convert the caller's IP address to a dotted string
9317c478bd9Sstevel@tonic-gate 	 */
9327c478bd9Sstevel@tonic-gate 	if (ca->sa_family == AF_INET) {
9337c478bd9Sstevel@tonic-gate 		b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
9347c478bd9Sstevel@tonic-gate 		(void) sprintf(buf, "%03d.%03d.%03d.%03d", b[0] & 0xFF,
935ed57cab9Srg 		    b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
9367c478bd9Sstevel@tonic-gate 	} else if (ca->sa_family == AF_INET6) {
9377c478bd9Sstevel@tonic-gate 		struct sockaddr_in6 *sin6;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 		sin6 = (struct sockaddr_in6 *)ca;
9407c478bd9Sstevel@tonic-gate 		(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
941ed57cab9Srg 		    buf, INET6_ADDRSTRLEN);
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	(void) snprintf(leaf, MAXNAMELEN, "%s-%llx", buf,
945d216dff5SRobert Mastors 	    (longlong_t)cp->rc_clientid);
9460dfe541eSEvan Layton 	rfs4_ss_clid_write(nsrv4, cp, leaf);
947cee86682Scalum }
9487c478bd9Sstevel@tonic-gate 
949cee86682Scalum /*
950cee86682Scalum  * Place client information into stable storage: 2/3.
951cee86682Scalum  * DSS: distributed stable storage: the file may need to be written to
952cee86682Scalum  * multiple directories.
953cee86682Scalum  */
954cee86682Scalum static void
rfs4_ss_clid_write(nfs4_srv_t * nsrv4,rfs4_client_t * cp,char * leaf)9550dfe541eSEvan Layton rfs4_ss_clid_write(nfs4_srv_t *nsrv4, rfs4_client_t *cp, char *leaf)
956cee86682Scalum {
957cee86682Scalum 	rfs4_servinst_t *sip;
958cee86682Scalum 
959cee86682Scalum 	/*
960cee86682Scalum 	 * It should be sufficient to write the leaf file to (all) DSS paths
961cee86682Scalum 	 * associated with just this client's instance. However, since our
962cee86682Scalum 	 * per-instance client grouping is solely temporal, HA-NFSv4 RG
963cee86682Scalum 	 * failover might result in us losing DSS data.
964cee86682Scalum 	 *
965cee86682Scalum 	 * Until the client grouping is improved, we must write the DSS data
966cee86682Scalum 	 * to all instances' paths. Start at the current instance, and
967cee86682Scalum 	 * walk the list backwards to the first.
968cee86682Scalum 	 */
9690dfe541eSEvan Layton 	mutex_enter(&nsrv4->servinst_lock);
9700dfe541eSEvan Layton 	for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev) {
971cee86682Scalum 		int i, npaths = sip->dss_npaths;
972cee86682Scalum 
973cee86682Scalum 		/* write the leaf file to all DSS paths */
974cee86682Scalum 		for (i = 0; i < npaths; i++) {
975cee86682Scalum 			rfs4_dss_path_t *dss_path = sip->dss_paths[i];
976cee86682Scalum 
977cee86682Scalum 			/* HA-NFSv4 path might have been failed-away from us */
978cee86682Scalum 			if (dss_path == NULL)
979cee86682Scalum 				continue;
980cee86682Scalum 
981cee86682Scalum 			rfs4_ss_clid_write_one(cp, dss_path->path, leaf);
982cee86682Scalum 		}
9837c478bd9Sstevel@tonic-gate 	}
9840dfe541eSEvan Layton 	mutex_exit(&nsrv4->servinst_lock);
985cee86682Scalum }
986cee86682Scalum 
987cee86682Scalum /*
988cee86682Scalum  * Place client information into stable storage: 3/3.
989cee86682Scalum  * Write the stable storage data to the requested file.
990cee86682Scalum  */
991cee86682Scalum static void
rfs4_ss_clid_write_one(rfs4_client_t * cp,char * dss_path,char * leaf)992cee86682Scalum rfs4_ss_clid_write_one(rfs4_client_t *cp, char *dss_path, char *leaf)
993cee86682Scalum {
994cee86682Scalum 	int ioflag;
995cee86682Scalum 	int file_vers = NFS4_SS_VERSION;
99697669b90Scalum 	size_t dirlen;
997cee86682Scalum 	struct uio uio;
998cee86682Scalum 	struct iovec iov[4];
999cee86682Scalum 	char *dir;
1000cee86682Scalum 	rfs4_ss_pn_t *ss_pn;
1001cee86682Scalum 	vnode_t *vp;
1002d216dff5SRobert Mastors 	nfs_client_id4 *cl_id4 = &(cp->rc_nfs_client);
1003cee86682Scalum 
1004cee86682Scalum 	/* allow 2 extra bytes for '/' & NUL */
100597669b90Scalum 	dirlen = strlen(dss_path) + strlen(NFS4_DSS_STATE_LEAF) + 2;
100697669b90Scalum 	dir = kmem_alloc(dirlen, KM_SLEEP);
1007cee86682Scalum 	(void) sprintf(dir, "%s/%s", dss_path, NFS4_DSS_STATE_LEAF);
1008cee86682Scalum 
100997669b90Scalum 	ss_pn = rfs4_ss_pnalloc(dir, leaf);
101097669b90Scalum 	/* rfs4_ss_pnalloc takes its own copy */
101197669b90Scalum 	kmem_free(dir, dirlen);
101297669b90Scalum 	if (ss_pn == NULL)
1013cee86682Scalum 		return;
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	if (vn_open(ss_pn->pn, UIO_SYSSPACE, FCREAT|FWRITE, 0600, &vp,
1016ed57cab9Srg 	    CRCREAT, 0)) {
10177c478bd9Sstevel@tonic-gate 		rfs4_ss_pnfree(ss_pn);
10187c478bd9Sstevel@tonic-gate 		return;
10197c478bd9Sstevel@tonic-gate 	}
10207c478bd9Sstevel@tonic-gate 
1021cee86682Scalum 	/*
1022cee86682Scalum 	 * We need to record leaf - i.e. the filename - so that we know
1023cee86682Scalum 	 * what to remove, in the future. However, the dir part of cp->ss_pn
1024cee86682Scalum 	 * should never be referenced directly, since it's potentially only
1025cee86682Scalum 	 * one of several paths with this leaf in it.
1026cee86682Scalum 	 */
1027d216dff5SRobert Mastors 	if (cp->rc_ss_pn != NULL) {
1028d216dff5SRobert Mastors 		if (strcmp(cp->rc_ss_pn->leaf, leaf) == 0) {
1029cee86682Scalum 			/* we've already recorded *this* leaf */
1030cee86682Scalum 			rfs4_ss_pnfree(ss_pn);
1031cee86682Scalum 		} else {
1032cee86682Scalum 			/* replace with this leaf */
1033d216dff5SRobert Mastors 			rfs4_ss_pnfree(cp->rc_ss_pn);
1034d216dff5SRobert Mastors 			cp->rc_ss_pn = ss_pn;
1035cee86682Scalum 		}
1036cee86682Scalum 	} else {
1037d216dff5SRobert Mastors 		cp->rc_ss_pn = ss_pn;
1038cee86682Scalum 	}
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate 	/*
10417c478bd9Sstevel@tonic-gate 	 * Build a scatter list that points to the nfs_client_id4
10427c478bd9Sstevel@tonic-gate 	 */
10437c478bd9Sstevel@tonic-gate 	iov[0].iov_base = (caddr_t)&file_vers;
10447c478bd9Sstevel@tonic-gate 	iov[0].iov_len = sizeof (int);
1045cee86682Scalum 	iov[1].iov_base = (caddr_t)&(cl_id4->verifier);
10467c478bd9Sstevel@tonic-gate 	iov[1].iov_len = NFS4_VERIFIER_SIZE;
10477c478bd9Sstevel@tonic-gate 	iov[2].iov_base = (caddr_t)&(cl_id4->id_len);
10487c478bd9Sstevel@tonic-gate 	iov[2].iov_len = sizeof (uint_t);
10497c478bd9Sstevel@tonic-gate 	iov[3].iov_base = (caddr_t)cl_id4->id_val;
10507c478bd9Sstevel@tonic-gate 	iov[3].iov_len = cl_id4->id_len;
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	uio.uio_iov = iov;
10537c478bd9Sstevel@tonic-gate 	uio.uio_iovcnt = 4;
10547c478bd9Sstevel@tonic-gate 	uio.uio_loffset = 0;
10557c478bd9Sstevel@tonic-gate 	uio.uio_segflg = UIO_SYSSPACE;
10567c478bd9Sstevel@tonic-gate 	uio.uio_llimit = (rlim64_t)MAXOFFSET_T;
10577c478bd9Sstevel@tonic-gate 	uio.uio_resid = cl_id4->id_len + sizeof (int) +
1058ed57cab9Srg 	    NFS4_VERIFIER_SIZE + sizeof (uint_t);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 	ioflag = uio.uio_fmode = (FWRITE|FSYNC);
10617c478bd9Sstevel@tonic-gate 	uio.uio_extflg = UIO_COPY_DEFAULT;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
10647c478bd9Sstevel@tonic-gate 	/* write the full client id to the file. */
10657c478bd9Sstevel@tonic-gate 	(void) VOP_WRITE(vp, &uio, ioflag, CRED(), NULL);
10667c478bd9Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
10677c478bd9Sstevel@tonic-gate 
1068da6c28aaSamw 	(void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED(), NULL);
10697c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate 
1072cee86682Scalum /*
1073cee86682Scalum  * DSS: distributed stable storage.
1074cee86682Scalum  * Unpack the list of paths passed by nfsd.
1075cee86682Scalum  * Use nvlist_alloc(9F) to manage the data.
1076cee86682Scalum  * The caller is responsible for allocating and freeing the buffer.
1077cee86682Scalum  */
1078cee86682Scalum int
rfs4_dss_setpaths(char * buf,size_t buflen)1079cee86682Scalum rfs4_dss_setpaths(char *buf, size_t buflen)
1080cee86682Scalum {
1081cee86682Scalum 	int error;
1082cee86682Scalum 
1083cee86682Scalum 	/*
1084cee86682Scalum 	 * If this is a "warm start", i.e. we previously had DSS paths,
1085cee86682Scalum 	 * preserve the old paths.
1086cee86682Scalum 	 */
1087cee86682Scalum 	if (rfs4_dss_paths != NULL) {
1088cee86682Scalum 		/*
1089cee86682Scalum 		 * Before we lose the ptr, destroy the nvlist and pathnames
1090cee86682Scalum 		 * array from the warm start before this one.
1091cee86682Scalum 		 */
1092aab83bb8SJosef 'Jeff' Sipek 		nvlist_free(rfs4_dss_oldpaths);
1093cee86682Scalum 		rfs4_dss_oldpaths = rfs4_dss_paths;
1094cee86682Scalum 	}
1095cee86682Scalum 
1096cee86682Scalum 	/* unpack the buffer into a searchable nvlist */
1097cee86682Scalum 	error = nvlist_unpack(buf, buflen, &rfs4_dss_paths, KM_SLEEP);
1098cee86682Scalum 	if (error)
1099cee86682Scalum 		return (error);
1100cee86682Scalum 
1101cee86682Scalum 	/*
1102cee86682Scalum 	 * Search the nvlist for the pathnames nvpair (which is the only nvpair
1103cee86682Scalum 	 * in the list, and record its location.
1104cee86682Scalum 	 */
1105cee86682Scalum 	error = nvlist_lookup_string_array(rfs4_dss_paths, NFS4_DSS_NVPAIR_NAME,
1106cee86682Scalum 	    &rfs4_dss_newpaths, &rfs4_dss_numnewpaths);
1107cee86682Scalum 	return (error);
1108cee86682Scalum }
1109cee86682Scalum 
11107c478bd9Sstevel@tonic-gate /*
11117c478bd9Sstevel@tonic-gate  * Ultimately the nfssys() call NFS4_CLR_STATE endsup here
11127c478bd9Sstevel@tonic-gate  * to find and mark the client for forced expire.
11137c478bd9Sstevel@tonic-gate  */
11147c478bd9Sstevel@tonic-gate static void
rfs4_client_scrub(rfs4_entry_t ent,void * arg)11157c478bd9Sstevel@tonic-gate rfs4_client_scrub(rfs4_entry_t ent, void *arg)
11167c478bd9Sstevel@tonic-gate {
11177c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp = (rfs4_client_t *)ent;
11187c478bd9Sstevel@tonic-gate 	struct nfs4clrst_args *clr = arg;
11197c478bd9Sstevel@tonic-gate 	struct sockaddr_in6 *ent_sin6;
11207c478bd9Sstevel@tonic-gate 	struct in6_addr  clr_in6;
11217c478bd9Sstevel@tonic-gate 	struct sockaddr_in  *ent_sin;
11227c478bd9Sstevel@tonic-gate 	struct in_addr   clr_in;
11237c478bd9Sstevel@tonic-gate 
1124d216dff5SRobert Mastors 	if (clr->addr_type != cp->rc_addr.ss_family) {
11257c478bd9Sstevel@tonic-gate 		return;
11267c478bd9Sstevel@tonic-gate 	}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	switch (clr->addr_type) {
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	case AF_INET6:
11317c478bd9Sstevel@tonic-gate 		/* copyin the address from user space */
11327c478bd9Sstevel@tonic-gate 		if (copyin(clr->ap, &clr_in6, sizeof (clr_in6))) {
11337c478bd9Sstevel@tonic-gate 			break;
11347c478bd9Sstevel@tonic-gate 		}
11357c478bd9Sstevel@tonic-gate 
1136d216dff5SRobert Mastors 		ent_sin6 = (struct sockaddr_in6 *)&cp->rc_addr;
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 		/*
11397c478bd9Sstevel@tonic-gate 		 * now compare, and if equivalent mark entry
11407c478bd9Sstevel@tonic-gate 		 * for forced expiration
11417c478bd9Sstevel@tonic-gate 		 */
11427c478bd9Sstevel@tonic-gate 		if (IN6_ARE_ADDR_EQUAL(&ent_sin6->sin6_addr, &clr_in6)) {
1143d216dff5SRobert Mastors 			cp->rc_forced_expire = 1;
11447c478bd9Sstevel@tonic-gate 		}
11457c478bd9Sstevel@tonic-gate 		break;
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	case AF_INET:
11487c478bd9Sstevel@tonic-gate 		/* copyin the address from user space */
11497c478bd9Sstevel@tonic-gate 		if (copyin(clr->ap, &clr_in, sizeof (clr_in))) {
11507c478bd9Sstevel@tonic-gate 			break;
11517c478bd9Sstevel@tonic-gate 		}
11527c478bd9Sstevel@tonic-gate 
1153d216dff5SRobert Mastors 		ent_sin = (struct sockaddr_in *)&cp->rc_addr;
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 		/*
11567c478bd9Sstevel@tonic-gate 		 * now compare, and if equivalent mark entry
11577c478bd9Sstevel@tonic-gate 		 * for forced expiration
11587c478bd9Sstevel@tonic-gate 		 */
11597c478bd9Sstevel@tonic-gate 		if (ent_sin->sin_addr.s_addr == clr_in.s_addr) {
1160d216dff5SRobert Mastors 			cp->rc_forced_expire = 1;
11617c478bd9Sstevel@tonic-gate 		}
11627c478bd9Sstevel@tonic-gate 		break;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	default:
11657c478bd9Sstevel@tonic-gate 		/* force this assert to fail */
11667c478bd9Sstevel@tonic-gate 		ASSERT(clr->addr_type != clr->addr_type);
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate /*
11717c478bd9Sstevel@tonic-gate  * This is called from nfssys() in order to clear server state
11727c478bd9Sstevel@tonic-gate  * for the specified client IP Address.
11737c478bd9Sstevel@tonic-gate  */
1174967a528aSDan McDonald int
rfs4_clear_client_state(struct nfs4clrst_args * clr)11757c478bd9Sstevel@tonic-gate rfs4_clear_client_state(struct nfs4clrst_args *clr)
11767c478bd9Sstevel@tonic-gate {
1177967a528aSDan McDonald 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
1178967a528aSDan McDonald 	int rc;
1179967a528aSDan McDonald 
1180967a528aSDan McDonald 	/* Once nfssrv is loaded, every zone should have one of these. */
1181967a528aSDan McDonald 	VERIFY(nsrv4 != NULL);
1182967a528aSDan McDonald 
1183967a528aSDan McDonald 	mutex_enter(&nsrv4->state_lock);
1184967a528aSDan McDonald 	/*
1185967a528aSDan McDonald 	 * But only after NFS service is running is the nfs4_server_state
1186967a528aSDan McDonald 	 * around. It's dirty (and needs the state_lock held), but all of the
1187967a528aSDan McDonald 	 * databases live deep in the nfs4_server_state, so it's the only thing
1188967a528aSDan McDonald 	 * to legitimately check prior to using anything. The pointers
1189967a528aSDan McDonald 	 * themselves may be stale.
1190967a528aSDan McDonald 	 */
1191967a528aSDan McDonald 	if (nsrv4->nfs4_server_state != NULL) {
1192967a528aSDan McDonald 		VERIFY(nsrv4->rfs4_client_tab != NULL);
1193967a528aSDan McDonald 		rfs4_dbe_walk(nsrv4->rfs4_client_tab, rfs4_client_scrub, clr);
1194967a528aSDan McDonald 		rc = 0;
1195967a528aSDan McDonald 	} else {
1196967a528aSDan McDonald 		rc = ENXIO;
1197967a528aSDan McDonald 	}
1198967a528aSDan McDonald 	mutex_exit(&nsrv4->state_lock);
1199967a528aSDan McDonald 	return (rc);
12007c478bd9Sstevel@tonic-gate }
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate /*
12037c478bd9Sstevel@tonic-gate  * Used to initialize the NFSv4 server's state or database.  All of
12040dfe541eSEvan Layton  * the tables are created and timers are set.
12057c478bd9Sstevel@tonic-gate  */
12067c478bd9Sstevel@tonic-gate void
rfs4_state_g_init(void)1207*f44e1126SVitaliy Gusev rfs4_state_g_init(void)
12087c478bd9Sstevel@tonic-gate {
12097c478bd9Sstevel@tonic-gate 	extern boolean_t rfs4_cpr_callb(void *, int);
12100dfe541eSEvan Layton 	/*
12110dfe541eSEvan Layton 	 * Add a CPR callback so that we can update client
12120dfe541eSEvan Layton 	 * access times to extend the lease after a suspend
12130dfe541eSEvan Layton 	 * and resume (using the same class as rpcmod/connmgr)
12140dfe541eSEvan Layton 	 */
12150dfe541eSEvan Layton 	cpr_id = callb_add(rfs4_cpr_callb, 0, CB_CL_CPR_RPC, "rfs4");
12167c478bd9Sstevel@tonic-gate 
12170dfe541eSEvan Layton 	/*
12180dfe541eSEvan Layton 	 * NFSv4 server state databases
12190dfe541eSEvan Layton 	 *
12200dfe541eSEvan Layton 	 * Initialized when the module is loaded and used by NFSv4 state
12210dfe541eSEvan Layton 	 * tables.  These kmem_cache free pools are used globally, the NFSv4
12220dfe541eSEvan Layton 	 * state tables which make use of these kmem_cache free pools are per
12230dfe541eSEvan Layton 	 * zone.
12240dfe541eSEvan Layton 	 *
12250dfe541eSEvan Layton 	 * initialize the global kmem_cache free pools which will be used by
12260dfe541eSEvan Layton 	 * the NFSv4 state tables.
12270dfe541eSEvan Layton 	 */
1228*f44e1126SVitaliy Gusev 	rfs4_client_mem_cache = nfs4_init_mem_cache("Client_entry_cache",
1229*f44e1126SVitaliy Gusev 	    2, sizeof (rfs4_client_t), 0);
1230*f44e1126SVitaliy Gusev 	rfs4_clntIP_mem_cache = nfs4_init_mem_cache("ClntIP_entry_cache",
1231*f44e1126SVitaliy Gusev 	    1, sizeof (rfs4_clntip_t), 1);
1232*f44e1126SVitaliy Gusev 	rfs4_openown_mem_cache = nfs4_init_mem_cache("OpenOwner_entry_cache",
1233*f44e1126SVitaliy Gusev 	    1, sizeof (rfs4_openowner_t), 2);
1234*f44e1126SVitaliy Gusev 	rfs4_openstID_mem_cache = nfs4_init_mem_cache("OpenStateID_entry_cache",
1235*f44e1126SVitaliy Gusev 	    3, sizeof (rfs4_state_t), 3);
1236*f44e1126SVitaliy Gusev 	rfs4_lockstID_mem_cache = nfs4_init_mem_cache("LockStateID_entry_cache",
1237*f44e1126SVitaliy Gusev 	    3, sizeof (rfs4_lo_state_t), 4);
1238*f44e1126SVitaliy Gusev 	rfs4_lockown_mem_cache = nfs4_init_mem_cache("Lockowner_entry_cache",
1239*f44e1126SVitaliy Gusev 	    2, sizeof (rfs4_lockowner_t), 5);
1240*f44e1126SVitaliy Gusev 	rfs4_file_mem_cache = nfs4_init_mem_cache("File_entry_cache",
1241*f44e1126SVitaliy Gusev 	    1, sizeof (rfs4_file_t), 6);
1242*f44e1126SVitaliy Gusev 	rfs4_delegstID_mem_cache =
1243*f44e1126SVitaliy Gusev 	    nfs4_init_mem_cache("DelegStateID_entry_cache", 2,
1244*f44e1126SVitaliy Gusev 	    sizeof (rfs4_deleg_state_t), 7);
1245*f44e1126SVitaliy Gusev 	rfs4_session_mem_cache = nfs4_init_mem_cache("Session_entry_cache",
1246*f44e1126SVitaliy Gusev 	    1, sizeof (rfs4_session_t), 8);
12470dfe541eSEvan Layton }
12480dfe541eSEvan Layton 
12490dfe541eSEvan Layton 
12500dfe541eSEvan Layton /*
12510dfe541eSEvan Layton  * Used at server shutdown to cleanup all of the NFSv4 server's structures
12520dfe541eSEvan Layton  * and other state.
12530dfe541eSEvan Layton  */
12540dfe541eSEvan Layton void
rfs4_state_g_fini(void)1255*f44e1126SVitaliy Gusev rfs4_state_g_fini(void)
12560dfe541eSEvan Layton {
12570dfe541eSEvan Layton 	int i;
12587c478bd9Sstevel@tonic-gate 	/*
12590dfe541eSEvan Layton 	 * Cleanup the CPR callback.
12607c478bd9Sstevel@tonic-gate 	 */
12610dfe541eSEvan Layton 	if (cpr_id)
12620dfe541eSEvan Layton 		(void) callb_delete(cpr_id);
12630dfe541eSEvan Layton 
12640dfe541eSEvan Layton 	/* free the NFSv4 state databases */
12650dfe541eSEvan Layton 	for (i = 0; i < RFS4_DB_MEM_CACHE_NUM; i++) {
12660dfe541eSEvan Layton 		kmem_cache_destroy(rfs4_db_mem_cache_table[i].r_db_mem_cache);
12670dfe541eSEvan Layton 		rfs4_db_mem_cache_table[i].r_db_mem_cache = NULL;
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate 
12700dfe541eSEvan Layton 	rfs4_client_mem_cache = NULL;
12710dfe541eSEvan Layton 	rfs4_clntIP_mem_cache = NULL;
12720dfe541eSEvan Layton 	rfs4_openown_mem_cache = NULL;
12730dfe541eSEvan Layton 	rfs4_openstID_mem_cache = NULL;
12740dfe541eSEvan Layton 	rfs4_lockstID_mem_cache = NULL;
12750dfe541eSEvan Layton 	rfs4_lockown_mem_cache = NULL;
12760dfe541eSEvan Layton 	rfs4_file_mem_cache = NULL;
12770dfe541eSEvan Layton 	rfs4_delegstID_mem_cache = NULL;
1278*f44e1126SVitaliy Gusev 	rfs4_session_mem_cache = NULL;
12790dfe541eSEvan Layton 
12800dfe541eSEvan Layton 	/* DSS: distributed stable storage */
12810dfe541eSEvan Layton 	nvlist_free(rfs4_dss_oldpaths);
12820dfe541eSEvan Layton 	nvlist_free(rfs4_dss_paths);
12830dfe541eSEvan Layton 	rfs4_dss_paths = rfs4_dss_oldpaths = NULL;
12840dfe541eSEvan Layton }
12850dfe541eSEvan Layton 
12860dfe541eSEvan Layton /*
12870dfe541eSEvan Layton  * Used to initialize the per zone NFSv4 server's state
12880dfe541eSEvan Layton  */
12890dfe541eSEvan Layton void
rfs4_state_zone_init(nfs4_srv_t * nsrv4)12900dfe541eSEvan Layton rfs4_state_zone_init(nfs4_srv_t *nsrv4)
12910dfe541eSEvan Layton {
12920dfe541eSEvan Layton 	time_t start_time;
12930dfe541eSEvan Layton 	int start_grace;
12940dfe541eSEvan Layton 	char *dss_path = NFS4_DSS_VAR_DIR;
12950dfe541eSEvan Layton 
12960dfe541eSEvan Layton 	/* DSS: distributed stable storage: initialise served paths list */
12970dfe541eSEvan Layton 	nsrv4->dss_pathlist = NULL;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 	/*
13007c478bd9Sstevel@tonic-gate 	 * Set the boot time.  If the server
13017c478bd9Sstevel@tonic-gate 	 * has been restarted quickly and has had the opportunity to
13027c478bd9Sstevel@tonic-gate 	 * service clients, then the start_time needs to be bumped
13037c478bd9Sstevel@tonic-gate 	 * regardless.  A small window but it exists...
13047c478bd9Sstevel@tonic-gate 	 */
130525a1318cSMarcel Telka 	start_time = gethrestime_sec();
13060dfe541eSEvan Layton 	if (nsrv4->rfs4_start_time < start_time)
13070dfe541eSEvan Layton 		nsrv4->rfs4_start_time = start_time;
13087c478bd9Sstevel@tonic-gate 	else
13090dfe541eSEvan Layton 		nsrv4->rfs4_start_time++;
1310cee86682Scalum 
13117c478bd9Sstevel@tonic-gate 	/*
13127c478bd9Sstevel@tonic-gate 	 * Create the first server instance, or a new one if the server has
13137c478bd9Sstevel@tonic-gate 	 * been restarted; see above comments on rfs4_start_time. Don't
13147c478bd9Sstevel@tonic-gate 	 * start its grace period; that will be done later, to maximise the
13157c478bd9Sstevel@tonic-gate 	 * clients' recovery window.
13167c478bd9Sstevel@tonic-gate 	 */
13177c478bd9Sstevel@tonic-gate 	start_grace = 0;
13180dfe541eSEvan Layton 	if (curzone == global_zone && rfs4_dss_numnewpaths > 0) {
13190dfe541eSEvan Layton 		int i;
13200dfe541eSEvan Layton 		char **dss_allpaths = NULL;
13210dfe541eSEvan Layton 		dss_allpaths = kmem_alloc(sizeof (char *) *
13220dfe541eSEvan Layton 		    (rfs4_dss_numnewpaths + 1), KM_SLEEP);
13230dfe541eSEvan Layton 		/*
13240dfe541eSEvan Layton 		 * Add the default path into the list of paths for saving
13250dfe541eSEvan Layton 		 * state informantion.
13260dfe541eSEvan Layton 		 */
13270dfe541eSEvan Layton 		dss_allpaths[0] = dss_path;
13280dfe541eSEvan Layton 		for (i = 0; i < rfs4_dss_numnewpaths; i++) {
13290dfe541eSEvan Layton 			dss_allpaths[i + 1] = rfs4_dss_newpaths[i];
13300dfe541eSEvan Layton 		}
13310dfe541eSEvan Layton 		rfs4_servinst_create(nsrv4, start_grace,
13320dfe541eSEvan Layton 		    (rfs4_dss_numnewpaths + 1), dss_allpaths);
13330dfe541eSEvan Layton 		kmem_free(dss_allpaths,
13340dfe541eSEvan Layton 		    (sizeof (char *) * (rfs4_dss_numnewpaths + 1)));
13350dfe541eSEvan Layton 	} else {
13360dfe541eSEvan Layton 		rfs4_servinst_create(nsrv4, start_grace, 1, &dss_path);
13370dfe541eSEvan Layton 	}
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/* reset the "first NFSv4 request" status */
13400dfe541eSEvan Layton 	nsrv4->seen_first_compound = 0;
13410dfe541eSEvan Layton 
13420dfe541eSEvan Layton 	mutex_enter(&nsrv4->state_lock);
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	/*
13450dfe541eSEvan Layton 	 * If the server state database has already been initialized,
13460dfe541eSEvan Layton 	 * skip it
13477c478bd9Sstevel@tonic-gate 	 */
13480dfe541eSEvan Layton 	if (nsrv4->nfs4_server_state != NULL) {
13490dfe541eSEvan Layton 		mutex_exit(&nsrv4->state_lock);
13500dfe541eSEvan Layton 		return;
13510dfe541eSEvan Layton 	}
13520dfe541eSEvan Layton 
13530dfe541eSEvan Layton 	rw_init(&nsrv4->rfs4_findclient_lock, NULL, RW_DEFAULT, NULL);
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	/* set the various cache timers for table creation */
13560dfe541eSEvan Layton 	if (nsrv4->rfs4_client_cache_time == 0)
13570dfe541eSEvan Layton 		nsrv4->rfs4_client_cache_time = CLIENT_CACHE_TIME;
13580dfe541eSEvan Layton 	if (nsrv4->rfs4_openowner_cache_time == 0)
13590dfe541eSEvan Layton 		nsrv4->rfs4_openowner_cache_time = OPENOWNER_CACHE_TIME;
13600dfe541eSEvan Layton 	if (nsrv4->rfs4_state_cache_time == 0)
13610dfe541eSEvan Layton 		nsrv4->rfs4_state_cache_time = STATE_CACHE_TIME;
13620dfe541eSEvan Layton 	if (nsrv4->rfs4_lo_state_cache_time == 0)
13630dfe541eSEvan Layton 		nsrv4->rfs4_lo_state_cache_time = LO_STATE_CACHE_TIME;
13640dfe541eSEvan Layton 	if (nsrv4->rfs4_lockowner_cache_time == 0)
13650dfe541eSEvan Layton 		nsrv4->rfs4_lockowner_cache_time = LOCKOWNER_CACHE_TIME;
13660dfe541eSEvan Layton 	if (nsrv4->rfs4_file_cache_time == 0)
13670dfe541eSEvan Layton 		nsrv4->rfs4_file_cache_time = FILE_CACHE_TIME;
13680dfe541eSEvan Layton 	if (nsrv4->rfs4_deleg_state_cache_time == 0)
13690dfe541eSEvan Layton 		nsrv4->rfs4_deleg_state_cache_time = DELEG_STATE_CACHE_TIME;
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	/* Create the overall database to hold all server state */
13720dfe541eSEvan Layton 	nsrv4->nfs4_server_state = rfs4_database_create(rfs4_database_debug);
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	/* Now create the individual tables */
13750dfe541eSEvan Layton 	nsrv4->rfs4_client_cache_time *= rfs4_lease_time;
13760dfe541eSEvan Layton 	nsrv4->rfs4_client_tab = rfs4_table_create(nsrv4->nfs4_server_state,
1377ed57cab9Srg 	    "Client",
13780dfe541eSEvan Layton 	    nsrv4->rfs4_client_cache_time,
1379ed57cab9Srg 	    2,
1380ed57cab9Srg 	    rfs4_client_create,
1381ed57cab9Srg 	    rfs4_client_destroy,
1382ed57cab9Srg 	    rfs4_client_expiry,
1383ed57cab9Srg 	    sizeof (rfs4_client_t),
1384ed57cab9Srg 	    TABSIZE,
1385ed57cab9Srg 	    MAXTABSZ/8, 100);
13860dfe541eSEvan Layton 	nsrv4->rfs4_nfsclnt_idx = rfs4_index_create(nsrv4->rfs4_client_tab,
1387ed57cab9Srg 	    "nfs_client_id4", nfsclnt_hash,
1388ed57cab9Srg 	    nfsclnt_compare, nfsclnt_mkkey,
1389ed57cab9Srg 	    TRUE);
13900dfe541eSEvan Layton 	nsrv4->rfs4_clientid_idx = rfs4_index_create(nsrv4->rfs4_client_tab,
1391ed57cab9Srg 	    "client_id", clientid_hash,
1392ed57cab9Srg 	    clientid_compare, clientid_mkkey,
1393ed57cab9Srg 	    FALSE);
13947c478bd9Sstevel@tonic-gate 
13950dfe541eSEvan Layton 	nsrv4->rfs4_clntip_cache_time = 86400 * 365;	/* about a year */
13960dfe541eSEvan Layton 	nsrv4->rfs4_clntip_tab = rfs4_table_create(nsrv4->nfs4_server_state,
13972f172c55SRobert Thurlow 	    "ClntIP",
13980dfe541eSEvan Layton 	    nsrv4->rfs4_clntip_cache_time,
13992f172c55SRobert Thurlow 	    1,
14002f172c55SRobert Thurlow 	    rfs4_clntip_create,
14012f172c55SRobert Thurlow 	    rfs4_clntip_destroy,
14022f172c55SRobert Thurlow 	    rfs4_clntip_expiry,
14032f172c55SRobert Thurlow 	    sizeof (rfs4_clntip_t),
14042f172c55SRobert Thurlow 	    TABSIZE,
14052f172c55SRobert Thurlow 	    MAXTABSZ, 100);
14060dfe541eSEvan Layton 	nsrv4->rfs4_clntip_idx = rfs4_index_create(nsrv4->rfs4_clntip_tab,
14072f172c55SRobert Thurlow 	    "client_ip", clntip_hash,
14082f172c55SRobert Thurlow 	    clntip_compare, clntip_mkkey,
14092f172c55SRobert Thurlow 	    TRUE);
14102f172c55SRobert Thurlow 
14110dfe541eSEvan Layton 	nsrv4->rfs4_openowner_cache_time *= rfs4_lease_time;
14120dfe541eSEvan Layton 	nsrv4->rfs4_openowner_tab = rfs4_table_create(nsrv4->nfs4_server_state,
1413ed57cab9Srg 	    "OpenOwner",
14140dfe541eSEvan Layton 	    nsrv4->rfs4_openowner_cache_time,
1415ed57cab9Srg 	    1,
1416ed57cab9Srg 	    rfs4_openowner_create,
1417ed57cab9Srg 	    rfs4_openowner_destroy,
1418ed57cab9Srg 	    rfs4_openowner_expiry,
1419ed57cab9Srg 	    sizeof (rfs4_openowner_t),
1420ed57cab9Srg 	    TABSIZE,
1421ed57cab9Srg 	    MAXTABSZ, 100);
14220dfe541eSEvan Layton 	nsrv4->rfs4_openowner_idx = rfs4_index_create(nsrv4->rfs4_openowner_tab,
1423ed57cab9Srg 	    "open_owner4", openowner_hash,
1424ed57cab9Srg 	    openowner_compare,
1425ed57cab9Srg 	    openowner_mkkey, TRUE);
14267c478bd9Sstevel@tonic-gate 
14270dfe541eSEvan Layton 	nsrv4->rfs4_state_cache_time *= rfs4_lease_time;
14280dfe541eSEvan Layton 	nsrv4->rfs4_state_tab = rfs4_table_create(nsrv4->nfs4_server_state,
1429ed57cab9Srg 	    "OpenStateID",
14300dfe541eSEvan Layton 	    nsrv4->rfs4_state_cache_time,
1431ed57cab9Srg 	    3,
1432ed57cab9Srg 	    rfs4_state_create,
1433ed57cab9Srg 	    rfs4_state_destroy,
1434ed57cab9Srg 	    rfs4_state_expiry,
1435ed57cab9Srg 	    sizeof (rfs4_state_t),
1436ed57cab9Srg 	    TABSIZE,
1437ed57cab9Srg 	    MAXTABSZ, 100);
1438ed57cab9Srg 
14390dfe541eSEvan Layton 	/* CSTYLED */
14400dfe541eSEvan Layton 	nsrv4->rfs4_state_owner_file_idx = rfs4_index_create(nsrv4->rfs4_state_tab,
1441ed57cab9Srg 	    "Openowner-File",
1442ed57cab9Srg 	    state_owner_file_hash,
1443ed57cab9Srg 	    state_owner_file_compare,
1444ed57cab9Srg 	    state_owner_file_mkkey, TRUE);
1445ed57cab9Srg 
14460dfe541eSEvan Layton 	nsrv4->rfs4_state_idx = rfs4_index_create(nsrv4->rfs4_state_tab,
1447ed57cab9Srg 	    "State-id", state_hash,
1448ed57cab9Srg 	    state_compare, state_mkkey, FALSE);
1449ed57cab9Srg 
14500dfe541eSEvan Layton 	nsrv4->rfs4_state_file_idx = rfs4_index_create(nsrv4->rfs4_state_tab,
1451ed57cab9Srg 	    "File", state_file_hash,
1452ed57cab9Srg 	    state_file_compare, state_file_mkkey,
1453ed57cab9Srg 	    FALSE);
14547c478bd9Sstevel@tonic-gate 
14550dfe541eSEvan Layton 	nsrv4->rfs4_lo_state_cache_time *= rfs4_lease_time;
14560dfe541eSEvan Layton 	nsrv4->rfs4_lo_state_tab = rfs4_table_create(nsrv4->nfs4_server_state,
1457ed57cab9Srg 	    "LockStateID",
14580dfe541eSEvan Layton 	    nsrv4->rfs4_lo_state_cache_time,
1459ed57cab9Srg 	    2,
1460ed57cab9Srg 	    rfs4_lo_state_create,
1461ed57cab9Srg 	    rfs4_lo_state_destroy,
1462ed57cab9Srg 	    rfs4_lo_state_expiry,
1463ed57cab9Srg 	    sizeof (rfs4_lo_state_t),
1464ed57cab9Srg 	    TABSIZE,
1465ed57cab9Srg 	    MAXTABSZ, 100);
1466ed57cab9Srg 
14670dfe541eSEvan Layton 	/* CSTYLED */
14680dfe541eSEvan Layton 	nsrv4->rfs4_lo_state_owner_idx = rfs4_index_create(nsrv4->rfs4_lo_state_tab,
1469ed57cab9Srg 	    "lockownerxstate",
1470ed57cab9Srg 	    lo_state_lo_hash,
1471ed57cab9Srg 	    lo_state_lo_compare,
1472ed57cab9Srg 	    lo_state_lo_mkkey, TRUE);
1473ed57cab9Srg 
14740dfe541eSEvan Layton 	nsrv4->rfs4_lo_state_idx = rfs4_index_create(nsrv4->rfs4_lo_state_tab,
1475ed57cab9Srg 	    "State-id",
1476ed57cab9Srg 	    lo_state_hash, lo_state_compare,
1477ed57cab9Srg 	    lo_state_mkkey, FALSE);
14787c478bd9Sstevel@tonic-gate 
14790dfe541eSEvan Layton 	nsrv4->rfs4_lockowner_cache_time *= rfs4_lease_time;
1480ed57cab9Srg 
14810dfe541eSEvan Layton 	nsrv4->rfs4_lockowner_tab = rfs4_table_create(nsrv4->nfs4_server_state,
1482ed57cab9Srg 	    "Lockowner",
14830dfe541eSEvan Layton 	    nsrv4->rfs4_lockowner_cache_time,
1484ed57cab9Srg 	    2,
1485ed57cab9Srg 	    rfs4_lockowner_create,
1486ed57cab9Srg 	    rfs4_lockowner_destroy,
1487ed57cab9Srg 	    rfs4_lockowner_expiry,
1488ed57cab9Srg 	    sizeof (rfs4_lockowner_t),
1489ed57cab9Srg 	    TABSIZE,
1490ed57cab9Srg 	    MAXTABSZ, 100);
1491ed57cab9Srg 
14920dfe541eSEvan Layton 	nsrv4->rfs4_lockowner_idx = rfs4_index_create(nsrv4->rfs4_lockowner_tab,
1493ed57cab9Srg 	    "lock_owner4", lockowner_hash,
1494ed57cab9Srg 	    lockowner_compare,
1495ed57cab9Srg 	    lockowner_mkkey, TRUE);
1496ed57cab9Srg 
14970dfe541eSEvan Layton 	/* CSTYLED */
14980dfe541eSEvan Layton 	nsrv4->rfs4_lockowner_pid_idx = rfs4_index_create(nsrv4->rfs4_lockowner_tab,
1499ed57cab9Srg 	    "pid", pid_hash,
1500ed57cab9Srg 	    pid_compare, pid_mkkey,
1501ed57cab9Srg 	    FALSE);
15027c478bd9Sstevel@tonic-gate 
15030dfe541eSEvan Layton 	nsrv4->rfs4_file_cache_time *= rfs4_lease_time;
15040dfe541eSEvan Layton 	nsrv4->rfs4_file_tab = rfs4_table_create(nsrv4->nfs4_server_state,
1505ed57cab9Srg 	    "File",
15060dfe541eSEvan Layton 	    nsrv4->rfs4_file_cache_time,
1507ed57cab9Srg 	    1,
1508ed57cab9Srg 	    rfs4_file_create,
1509ed57cab9Srg 	    rfs4_file_destroy,
1510ed57cab9Srg 	    NULL,
1511ed57cab9Srg 	    sizeof (rfs4_file_t),
1512ed57cab9Srg 	    TABSIZE,
1513ed57cab9Srg 	    MAXTABSZ, -1);
1514ed57cab9Srg 
15150dfe541eSEvan Layton 	nsrv4->rfs4_file_idx = rfs4_index_create(nsrv4->rfs4_file_tab,
1516ed57cab9Srg 	    "Filehandle", file_hash,
1517ed57cab9Srg 	    file_compare, file_mkkey, TRUE);
15187c478bd9Sstevel@tonic-gate 
15190dfe541eSEvan Layton 	nsrv4->rfs4_deleg_state_cache_time *= rfs4_lease_time;
15200dfe541eSEvan Layton 	/* CSTYLED */
15210dfe541eSEvan Layton 	nsrv4->rfs4_deleg_state_tab = rfs4_table_create(nsrv4->nfs4_server_state,
1522ed57cab9Srg 	    "DelegStateID",
15230dfe541eSEvan Layton 	    nsrv4->rfs4_deleg_state_cache_time,
1524ed57cab9Srg 	    2,
1525ed57cab9Srg 	    rfs4_deleg_state_create,
1526ed57cab9Srg 	    rfs4_deleg_state_destroy,
1527ed57cab9Srg 	    rfs4_deleg_state_expiry,
1528ed57cab9Srg 	    sizeof (rfs4_deleg_state_t),
1529ed57cab9Srg 	    TABSIZE,
1530ed57cab9Srg 	    MAXTABSZ, 100);
15310dfe541eSEvan Layton 	nsrv4->rfs4_deleg_idx = rfs4_index_create(nsrv4->rfs4_deleg_state_tab,
1532ed57cab9Srg 	    "DelegByFileClient",
1533ed57cab9Srg 	    deleg_hash,
1534ed57cab9Srg 	    deleg_compare,
1535ed57cab9Srg 	    deleg_mkkey, TRUE);
1536ed57cab9Srg 
15370dfe541eSEvan Layton 	/* CSTYLED */
15380dfe541eSEvan Layton 	nsrv4->rfs4_deleg_state_idx = rfs4_index_create(nsrv4->rfs4_deleg_state_tab,
1539ed57cab9Srg 	    "DelegState",
1540ed57cab9Srg 	    deleg_state_hash,
1541ed57cab9Srg 	    deleg_state_compare,
1542ed57cab9Srg 	    deleg_state_mkkey, FALSE);
15437c478bd9Sstevel@tonic-gate 
1544*f44e1126SVitaliy Gusev 	rfs4x_state_init_locked(nsrv4);
1545*f44e1126SVitaliy Gusev 
15460dfe541eSEvan Layton 	mutex_exit(&nsrv4->state_lock);
15470dfe541eSEvan Layton 
15487c478bd9Sstevel@tonic-gate 	/*
15497c478bd9Sstevel@tonic-gate 	 * Init the stable storage.
15507c478bd9Sstevel@tonic-gate 	 */
15510dfe541eSEvan Layton 	rfs4_ss_init(nsrv4);
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate /*
15550dfe541eSEvan Layton  * Used at server shutdown to cleanup all of NFSv4 server's zone structures
15560dfe541eSEvan Layton  * and state.
15577c478bd9Sstevel@tonic-gate  */
15587c478bd9Sstevel@tonic-gate void
rfs4_state_zone_fini(void)1559*f44e1126SVitaliy Gusev rfs4_state_zone_fini(void)
15607c478bd9Sstevel@tonic-gate {
15617c478bd9Sstevel@tonic-gate 	rfs4_database_t *dbp;
15620dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
15630dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
15640dfe541eSEvan Layton 
15650dfe541eSEvan Layton 	rfs4_set_deleg_policy(nsrv4, SRV_NEVER_DELEGATE);
15660dfe541eSEvan Layton 
15670dfe541eSEvan Layton 	/*
15680dfe541eSEvan Layton 	 * Clean up any dangling stable storage structures BEFORE calling
15690dfe541eSEvan Layton 	 * rfs4_servinst_destroy_all() so there are no dangling structures
15700dfe541eSEvan Layton 	 * (i.e. the srvinsts are all cleared of danglers BEFORE they get
15710dfe541eSEvan Layton 	 * freed).
15720dfe541eSEvan Layton 	 */
15730dfe541eSEvan Layton 	rfs4_ss_fini(nsrv4);
15747c478bd9Sstevel@tonic-gate 
15750dfe541eSEvan Layton 	mutex_enter(&nsrv4->state_lock);
15767c478bd9Sstevel@tonic-gate 
15770dfe541eSEvan Layton 	if (nsrv4->nfs4_server_state == NULL) {
15780dfe541eSEvan Layton 		mutex_exit(&nsrv4->state_lock);
15797c478bd9Sstevel@tonic-gate 		return;
15807c478bd9Sstevel@tonic-gate 	}
15817c478bd9Sstevel@tonic-gate 
1582*f44e1126SVitaliy Gusev 	rfs4x_state_fini(nsrv4);
1583*f44e1126SVitaliy Gusev 
15840dfe541eSEvan Layton 	/* destroy server instances and current instance ptr */
15850dfe541eSEvan Layton 	rfs4_servinst_destroy_all(nsrv4);
15867c478bd9Sstevel@tonic-gate 
15870dfe541eSEvan Layton 	/* reset the "first NFSv4 request" status */
15880dfe541eSEvan Layton 	nsrv4->seen_first_compound = 0;
15897c478bd9Sstevel@tonic-gate 
15900dfe541eSEvan Layton 	dbp = nsrv4->nfs4_server_state;
15910dfe541eSEvan Layton 	nsrv4->nfs4_server_state = NULL;
15927c478bd9Sstevel@tonic-gate 
15930dfe541eSEvan Layton 	rw_destroy(&nsrv4->rfs4_findclient_lock);
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	/* First stop all of the reaper threads in the database */
15967c478bd9Sstevel@tonic-gate 	rfs4_database_shutdown(dbp);
15970dfe541eSEvan Layton 
15980dfe541eSEvan Layton 	/*
15990dfe541eSEvan Layton 	 * WARNING: There may be consumers of the rfs4 database still
16000dfe541eSEvan Layton 	 * active as we destroy these.  IF that's the case, consider putting
16010dfe541eSEvan Layton 	 * some of their _zone_fini()-like functions into the zsd key as
16020dfe541eSEvan Layton 	 * ~~SHUTDOWN~~ functions instead of ~~DESTROY~~ functions.  We can
16030dfe541eSEvan Layton 	 * maintain some ordering guarantees better that way.
16040dfe541eSEvan Layton 	 */
16050dfe541eSEvan Layton 	/* Now destroy/release the database tables */
16067c478bd9Sstevel@tonic-gate 	rfs4_database_destroy(dbp);
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	/* Reset the cache timers for next time */
16090dfe541eSEvan Layton 	nsrv4->rfs4_client_cache_time = 0;
16100dfe541eSEvan Layton 	nsrv4->rfs4_openowner_cache_time = 0;
16110dfe541eSEvan Layton 	nsrv4->rfs4_state_cache_time = 0;
16120dfe541eSEvan Layton 	nsrv4->rfs4_lo_state_cache_time = 0;
16130dfe541eSEvan Layton 	nsrv4->rfs4_lockowner_cache_time = 0;
16140dfe541eSEvan Layton 	nsrv4->rfs4_file_cache_time = 0;
16150dfe541eSEvan Layton 	nsrv4->rfs4_deleg_state_cache_time = 0;
1616cee86682Scalum 
16170dfe541eSEvan Layton 	mutex_exit(&nsrv4->state_lock);
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate typedef union {
16217c478bd9Sstevel@tonic-gate 	struct {
16227c478bd9Sstevel@tonic-gate 		uint32_t start_time;
16237c478bd9Sstevel@tonic-gate 		uint32_t c_id;
16247c478bd9Sstevel@tonic-gate 	} impl_id;
16257c478bd9Sstevel@tonic-gate 	clientid4 id4;
16267c478bd9Sstevel@tonic-gate } cid;
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate static int foreign_stateid(stateid_t *id);
16297c478bd9Sstevel@tonic-gate static int foreign_clientid(cid *cidp);
16307c478bd9Sstevel@tonic-gate static void embed_nodeid(cid *cidp);
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate typedef union {
16337c478bd9Sstevel@tonic-gate 	struct {
16347c478bd9Sstevel@tonic-gate 		uint32_t c_id;
16357c478bd9Sstevel@tonic-gate 		uint32_t gen_num;
16367c478bd9Sstevel@tonic-gate 	} cv_impl;
16377c478bd9Sstevel@tonic-gate 	verifier4	confirm_verf;
16387c478bd9Sstevel@tonic-gate } scid_confirm_verf;
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate static uint32_t
clientid_hash(void * key)16417c478bd9Sstevel@tonic-gate clientid_hash(void *key)
16427c478bd9Sstevel@tonic-gate {
16437c478bd9Sstevel@tonic-gate 	cid *idp = key;
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	return (idp->impl_id.c_id);
16467c478bd9Sstevel@tonic-gate }
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate static bool_t
clientid_compare(rfs4_entry_t entry,void * key)16497c478bd9Sstevel@tonic-gate clientid_compare(rfs4_entry_t entry, void *key)
16507c478bd9Sstevel@tonic-gate {
1651d216dff5SRobert Mastors 	rfs4_client_t *cp = (rfs4_client_t *)entry;
16527c478bd9Sstevel@tonic-gate 	clientid4 *idp = key;
16537c478bd9Sstevel@tonic-gate 
1654d216dff5SRobert Mastors 	return (*idp == cp->rc_clientid);
16557c478bd9Sstevel@tonic-gate }
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate static void *
clientid_mkkey(rfs4_entry_t entry)16587c478bd9Sstevel@tonic-gate clientid_mkkey(rfs4_entry_t entry)
16597c478bd9Sstevel@tonic-gate {
1660d216dff5SRobert Mastors 	rfs4_client_t *cp = (rfs4_client_t *)entry;
16617c478bd9Sstevel@tonic-gate 
1662d216dff5SRobert Mastors 	return (&cp->rc_clientid);
16637c478bd9Sstevel@tonic-gate }
16647c478bd9Sstevel@tonic-gate 
16657c478bd9Sstevel@tonic-gate static uint32_t
nfsclnt_hash(void * key)16667c478bd9Sstevel@tonic-gate nfsclnt_hash(void *key)
16677c478bd9Sstevel@tonic-gate {
16687c478bd9Sstevel@tonic-gate 	nfs_client_id4 *client = key;
16697c478bd9Sstevel@tonic-gate 	int i;
16707c478bd9Sstevel@tonic-gate 	uint32_t hash = 0;
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	for (i = 0; i < client->id_len; i++) {
16737c478bd9Sstevel@tonic-gate 		hash <<= 1;
16747c478bd9Sstevel@tonic-gate 		hash += (uint_t)client->id_val[i];
16757c478bd9Sstevel@tonic-gate 	}
16767c478bd9Sstevel@tonic-gate 	return (hash);
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate static bool_t
nfsclnt_compare(rfs4_entry_t entry,void * key)16817c478bd9Sstevel@tonic-gate nfsclnt_compare(rfs4_entry_t entry, void *key)
16827c478bd9Sstevel@tonic-gate {
1683d216dff5SRobert Mastors 	rfs4_client_t *cp = (rfs4_client_t *)entry;
16847c478bd9Sstevel@tonic-gate 	nfs_client_id4 *nfs_client = key;
16857c478bd9Sstevel@tonic-gate 
1686d216dff5SRobert Mastors 	if (cp->rc_nfs_client.id_len != nfs_client->id_len)
16877c478bd9Sstevel@tonic-gate 		return (FALSE);
16887c478bd9Sstevel@tonic-gate 
1689d216dff5SRobert Mastors 	return (bcmp(cp->rc_nfs_client.id_val, nfs_client->id_val,
1690ed57cab9Srg 	    nfs_client->id_len) == 0);
16917c478bd9Sstevel@tonic-gate }
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate static void *
nfsclnt_mkkey(rfs4_entry_t entry)16947c478bd9Sstevel@tonic-gate nfsclnt_mkkey(rfs4_entry_t entry)
16957c478bd9Sstevel@tonic-gate {
1696d216dff5SRobert Mastors 	rfs4_client_t *cp = (rfs4_client_t *)entry;
16977c478bd9Sstevel@tonic-gate 
1698d216dff5SRobert Mastors 	return (&cp->rc_nfs_client);
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate static bool_t
rfs4_client_expiry(rfs4_entry_t u_entry)17027c478bd9Sstevel@tonic-gate rfs4_client_expiry(rfs4_entry_t u_entry)
17037c478bd9Sstevel@tonic-gate {
17047c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp = (rfs4_client_t *)u_entry;
17057c478bd9Sstevel@tonic-gate 	bool_t cp_expired;
17067c478bd9Sstevel@tonic-gate 
1707fbd8dcf9SGerald Thornbrugh 	if (rfs4_dbe_is_invalid(cp->rc_dbe)) {
1708fbd8dcf9SGerald Thornbrugh 		cp->rc_ss_remove = 1;
17097c478bd9Sstevel@tonic-gate 		return (TRUE);
1710fbd8dcf9SGerald Thornbrugh 	}
17117c478bd9Sstevel@tonic-gate 	/*
17127c478bd9Sstevel@tonic-gate 	 * If the sysadmin has used clear_locks for this
17137c478bd9Sstevel@tonic-gate 	 * entry then forced_expire will be set and we
17147c478bd9Sstevel@tonic-gate 	 * want this entry to be reaped. Or the entry
17157c478bd9Sstevel@tonic-gate 	 * has exceeded its lease period.
17167c478bd9Sstevel@tonic-gate 	 */
1717d216dff5SRobert Mastors 	cp_expired = (cp->rc_forced_expire ||
1718d216dff5SRobert Mastors 	    (gethrestime_sec() - cp->rc_last_access
1719ed57cab9Srg 	    > rfs4_lease_time));
1720cee86682Scalum 
1721d216dff5SRobert Mastors 	if (!cp->rc_ss_remove && cp_expired)
1722d216dff5SRobert Mastors 		cp->rc_ss_remove = 1;
17237c478bd9Sstevel@tonic-gate 	return (cp_expired);
17247c478bd9Sstevel@tonic-gate }
17257c478bd9Sstevel@tonic-gate 
1726cee86682Scalum /*
1727cee86682Scalum  * Remove the leaf file from all distributed stable storage paths.
1728cee86682Scalum  */
1729cee86682Scalum static void
rfs4_dss_remove_cpleaf(rfs4_client_t * cp)1730cee86682Scalum rfs4_dss_remove_cpleaf(rfs4_client_t *cp)
1731cee86682Scalum {
17320dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
1733fbd8dcf9SGerald Thornbrugh 	rfs4_servinst_t *sip;
1734d216dff5SRobert Mastors 	char *leaf = cp->rc_ss_pn->leaf;
1735cee86682Scalum 
1736fbd8dcf9SGerald Thornbrugh 	/*
1737fbd8dcf9SGerald Thornbrugh 	 * since the state files are written to all DSS
1738fbd8dcf9SGerald Thornbrugh 	 * paths we must remove this leaf file instance
1739fbd8dcf9SGerald Thornbrugh 	 * from all server instances.
1740fbd8dcf9SGerald Thornbrugh 	 */
1741fbd8dcf9SGerald Thornbrugh 
17420dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
17430dfe541eSEvan Layton 	mutex_enter(&nsrv4->servinst_lock);
17440dfe541eSEvan Layton 	for (sip = nsrv4->nfs4_cur_servinst; sip != NULL; sip = sip->prev) {
1745fbd8dcf9SGerald Thornbrugh 		/* remove the leaf file associated with this server instance */
1746fbd8dcf9SGerald Thornbrugh 		rfs4_dss_remove_leaf(sip, NFS4_DSS_STATE_LEAF, leaf);
1747fbd8dcf9SGerald Thornbrugh 	}
17480dfe541eSEvan Layton 	mutex_exit(&nsrv4->servinst_lock);
1749cee86682Scalum }
1750cee86682Scalum 
1751cee86682Scalum static void
rfs4_dss_remove_leaf(rfs4_servinst_t * sip,char * dir_leaf,char * leaf)1752cee86682Scalum rfs4_dss_remove_leaf(rfs4_servinst_t *sip, char *dir_leaf, char *leaf)
1753cee86682Scalum {
1754cee86682Scalum 	int i, npaths = sip->dss_npaths;
1755cee86682Scalum 
1756cee86682Scalum 	for (i = 0; i < npaths; i++) {
1757cee86682Scalum 		rfs4_dss_path_t *dss_path = sip->dss_paths[i];
1758cee86682Scalum 		char *path, *dir;
1759cee86682Scalum 		size_t pathlen;
1760cee86682Scalum 
1761cee86682Scalum 		/* the HA-NFSv4 path might have been failed-over away from us */
1762cee86682Scalum 		if (dss_path == NULL)
1763cee86682Scalum 			continue;
1764cee86682Scalum 
1765cee86682Scalum 		dir = dss_path->path;
1766cee86682Scalum 
1767cee86682Scalum 		/* allow 3 extra bytes for two '/' & a NUL */
1768cee86682Scalum 		pathlen = strlen(dir) + strlen(dir_leaf) + strlen(leaf) + 3;
1769cee86682Scalum 		path = kmem_alloc(pathlen, KM_SLEEP);
1770cee86682Scalum 		(void) sprintf(path, "%s/%s/%s", dir, dir_leaf, leaf);
1771cee86682Scalum 
1772cee86682Scalum 		(void) vn_remove(path, UIO_SYSSPACE, RMFILE);
1773cee86682Scalum 
1774cee86682Scalum 		kmem_free(path, pathlen);
1775cee86682Scalum 	}
1776cee86682Scalum }
1777cee86682Scalum 
17787c478bd9Sstevel@tonic-gate static void
rfs4_client_destroy(rfs4_entry_t u_entry)17797c478bd9Sstevel@tonic-gate rfs4_client_destroy(rfs4_entry_t u_entry)
17807c478bd9Sstevel@tonic-gate {
17817c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp = (rfs4_client_t *)u_entry;
17827c478bd9Sstevel@tonic-gate 
1783d216dff5SRobert Mastors 	mutex_destroy(cp->rc_cbinfo.cb_lock);
1784d216dff5SRobert Mastors 	cv_destroy(cp->rc_cbinfo.cb_cv);
1785d216dff5SRobert Mastors 	cv_destroy(cp->rc_cbinfo.cb_cv_nullcaller);
1786d216dff5SRobert Mastors 	list_destroy(&cp->rc_openownerlist);
17877c478bd9Sstevel@tonic-gate 
1788*f44e1126SVitaliy Gusev 	list_destroy(&cp->rc_sessions);
1789*f44e1126SVitaliy Gusev 
17907c478bd9Sstevel@tonic-gate 	/* free callback info */
1791d216dff5SRobert Mastors 	rfs4_cbinfo_free(&cp->rc_cbinfo);
17927c478bd9Sstevel@tonic-gate 
1793d216dff5SRobert Mastors 	if (cp->rc_cp_confirmed)
1794d216dff5SRobert Mastors 		rfs4_client_rele(cp->rc_cp_confirmed);
17957c478bd9Sstevel@tonic-gate 
1796d216dff5SRobert Mastors 	if (cp->rc_ss_pn) {
1797cee86682Scalum 		/* check if the stable storage files need to be removed */
1798d216dff5SRobert Mastors 		if (cp->rc_ss_remove)
1799cee86682Scalum 			rfs4_dss_remove_cpleaf(cp);
1800d216dff5SRobert Mastors 		rfs4_ss_pnfree(cp->rc_ss_pn);
18017c478bd9Sstevel@tonic-gate 	}
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	/* Free the client supplied client id */
1804d216dff5SRobert Mastors 	kmem_free(cp->rc_nfs_client.id_val, cp->rc_nfs_client.id_len);
18057c478bd9Sstevel@tonic-gate 
1806d216dff5SRobert Mastors 	if (cp->rc_sysidt != LM_NOSYSID)
1807d216dff5SRobert Mastors 		lm_free_sysidt(cp->rc_sysidt);
1808*f44e1126SVitaliy Gusev 
1809*f44e1126SVitaliy Gusev 	rfs4_free_cred_set(&cp->rc_cr_set);
18107c478bd9Sstevel@tonic-gate }
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate static bool_t
rfs4_client_create(rfs4_entry_t u_entry,void * arg)18137c478bd9Sstevel@tonic-gate rfs4_client_create(rfs4_entry_t u_entry, void *arg)
18147c478bd9Sstevel@tonic-gate {
18157c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp = (rfs4_client_t *)u_entry;
18167c478bd9Sstevel@tonic-gate 	nfs_client_id4 *client = (nfs_client_id4 *)arg;
18172f172c55SRobert Thurlow 	struct sockaddr *ca;
18187c478bd9Sstevel@tonic-gate 	cid *cidp;
18197c478bd9Sstevel@tonic-gate 	scid_confirm_verf *scvp;
18200dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
18210dfe541eSEvan Layton 
18220dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 	/* Get a clientid to give to the client */
1825d216dff5SRobert Mastors 	cidp = (cid *)&cp->rc_clientid;
18260dfe541eSEvan Layton 	cidp->impl_id.start_time = nsrv4->rfs4_start_time;
1827d216dff5SRobert Mastors 	cidp->impl_id.c_id = (uint32_t)rfs4_dbe_getid(cp->rc_dbe);
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 	/* If we are booted as a cluster node, embed our nodeid */
18307c478bd9Sstevel@tonic-gate 	if (cluster_bootflags & CLUSTER_BOOTED)
18317c478bd9Sstevel@tonic-gate 		embed_nodeid(cidp);
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate 	/* Allocate and copy client's client id value */
1834d216dff5SRobert Mastors 	cp->rc_nfs_client.id_val = kmem_alloc(client->id_len, KM_SLEEP);
1835d216dff5SRobert Mastors 	cp->rc_nfs_client.id_len = client->id_len;
1836d216dff5SRobert Mastors 	bcopy(client->id_val, cp->rc_nfs_client.id_val, client->id_len);
1837d216dff5SRobert Mastors 	cp->rc_nfs_client.verifier = client->verifier;
18387c478bd9Sstevel@tonic-gate 
18392f172c55SRobert Thurlow 	/* Copy client's IP address */
18402f172c55SRobert Thurlow 	ca = client->cl_addr;
18412f172c55SRobert Thurlow 	if (ca->sa_family == AF_INET)
18422f172c55SRobert Thurlow 		bcopy(ca, &cp->rc_addr, sizeof (struct sockaddr_in));
18432f172c55SRobert Thurlow 	else if (ca->sa_family == AF_INET6)
18442f172c55SRobert Thurlow 		bcopy(ca, &cp->rc_addr, sizeof (struct sockaddr_in6));
18452f172c55SRobert Thurlow 	cp->rc_nfs_client.cl_addr = (struct sockaddr *)&cp->rc_addr;
18462f172c55SRobert Thurlow 
18477c478bd9Sstevel@tonic-gate 	/* Init the value for the SETCLIENTID_CONFIRM verifier */
1848d216dff5SRobert Mastors 	scvp = (scid_confirm_verf *)&cp->rc_confirm_verf;
18497c478bd9Sstevel@tonic-gate 	scvp->cv_impl.c_id = cidp->impl_id.c_id;
18507c478bd9Sstevel@tonic-gate 	scvp->cv_impl.gen_num = 0;
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	/* An F_UNLKSYS has been done for this client */
1853d216dff5SRobert Mastors 	cp->rc_unlksys_completed = FALSE;
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	/* We need the client to ack us */
1856d216dff5SRobert Mastors 	cp->rc_need_confirm = TRUE;
1857d216dff5SRobert Mastors 	cp->rc_cp_confirmed = NULL;
1858*f44e1126SVitaliy Gusev 	cp->rc_destroying = FALSE;
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	/* TRUE all the time until the callback path actually fails */
1861d216dff5SRobert Mastors 	cp->rc_cbinfo.cb_notified_of_cb_path_down = TRUE;
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate 	/* Initialize the access time to now */
1864d216dff5SRobert Mastors 	cp->rc_last_access = gethrestime_sec();
18657c478bd9Sstevel@tonic-gate 
1866*f44e1126SVitaliy Gusev 	bzero(&cp->rc_cr_set, sizeof (cred_set_t));
18677c478bd9Sstevel@tonic-gate 
1868d216dff5SRobert Mastors 	cp->rc_sysidt = LM_NOSYSID;
18697c478bd9Sstevel@tonic-gate 
1870d216dff5SRobert Mastors 	list_create(&cp->rc_openownerlist, sizeof (rfs4_openowner_t),
1871d216dff5SRobert Mastors 	    offsetof(rfs4_openowner_t, ro_node));
18727c478bd9Sstevel@tonic-gate 
1873*f44e1126SVitaliy Gusev 	list_create(&cp->rc_sessions, sizeof (rfs4_session_t),
1874*f44e1126SVitaliy Gusev 	    offsetof(rfs4_session_t, sn_node));
1875*f44e1126SVitaliy Gusev 
18767c478bd9Sstevel@tonic-gate 	/* set up the callback control structure */
1877d216dff5SRobert Mastors 	cp->rc_cbinfo.cb_state = CB_UNINIT;
1878d216dff5SRobert Mastors 	mutex_init(cp->rc_cbinfo.cb_lock, NULL, MUTEX_DEFAULT, NULL);
1879d216dff5SRobert Mastors 	cv_init(cp->rc_cbinfo.cb_cv, NULL, CV_DEFAULT, NULL);
1880d216dff5SRobert Mastors 	cv_init(cp->rc_cbinfo.cb_cv_nullcaller, NULL, CV_DEFAULT, NULL);
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 	/*
18837c478bd9Sstevel@tonic-gate 	 * Associate the client_t with the current server instance.
18847c478bd9Sstevel@tonic-gate 	 * The hold is solely to satisfy the calling requirement of
18857c478bd9Sstevel@tonic-gate 	 * rfs4_servinst_assign(). In this case it's not strictly necessary.
18867c478bd9Sstevel@tonic-gate 	 */
1887d216dff5SRobert Mastors 	rfs4_dbe_hold(cp->rc_dbe);
18880dfe541eSEvan Layton 	rfs4_servinst_assign(nsrv4, cp, nsrv4->nfs4_cur_servinst);
1889d216dff5SRobert Mastors 	rfs4_dbe_rele(cp->rc_dbe);
18907c478bd9Sstevel@tonic-gate 
1891*f44e1126SVitaliy Gusev 	/*
1892*f44e1126SVitaliy Gusev 	 * NFSv4.1: See rfc8881, Section 18.36.4, eir_sequenceid
1893*f44e1126SVitaliy Gusev 	 * "Before the server replies to that EXCHANGE_ID
1894*f44e1126SVitaliy Gusev 	 * operation, it initializes the client ID slot to be equal to
1895*f44e1126SVitaliy Gusev 	 * eir_sequenceid - 1 (accounting for underflow), and records a
1896*f44e1126SVitaliy Gusev 	 * contrived CREATE_SESSION result with a "cached" result of
1897*f44e1126SVitaliy Gusev 	 * NFS4ERR_SEQ_MISORDERED."
1898*f44e1126SVitaliy Gusev 	 */
1899*f44e1126SVitaliy Gusev 	cp->rc_contrived.xi_sid = 1;
1900*f44e1126SVitaliy Gusev 	cp->rc_contrived.cs_status = NFS4ERR_SEQ_MISORDERED;
1901*f44e1126SVitaliy Gusev 
19027c478bd9Sstevel@tonic-gate 	return (TRUE);
19037c478bd9Sstevel@tonic-gate }
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate /*
19067c478bd9Sstevel@tonic-gate  * Caller wants to generate/update the setclientid_confirm verifier
19077c478bd9Sstevel@tonic-gate  * associated with a client.  This is done during the SETCLIENTID
19087c478bd9Sstevel@tonic-gate  * processing.
19097c478bd9Sstevel@tonic-gate  */
19107c478bd9Sstevel@tonic-gate void
rfs4_client_scv_next(rfs4_client_t * cp)19117c478bd9Sstevel@tonic-gate rfs4_client_scv_next(rfs4_client_t *cp)
19127c478bd9Sstevel@tonic-gate {
19137c478bd9Sstevel@tonic-gate 	scid_confirm_verf *scvp;
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	/* Init the value for the SETCLIENTID_CONFIRM verifier */
1916d216dff5SRobert Mastors 	scvp = (scid_confirm_verf *)&cp->rc_confirm_verf;
19177c478bd9Sstevel@tonic-gate 	scvp->cv_impl.gen_num++;
19187c478bd9Sstevel@tonic-gate }
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate void
rfs4_client_rele(rfs4_client_t * cp)19217c478bd9Sstevel@tonic-gate rfs4_client_rele(rfs4_client_t *cp)
19227c478bd9Sstevel@tonic-gate {
1923d216dff5SRobert Mastors 	rfs4_dbe_rele(cp->rc_dbe);
19247c478bd9Sstevel@tonic-gate }
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate rfs4_client_t *
rfs4_findclient(nfs_client_id4 * client,bool_t * create,rfs4_client_t * oldcp)19277c478bd9Sstevel@tonic-gate rfs4_findclient(nfs_client_id4 *client, bool_t *create,	rfs4_client_t *oldcp)
19287c478bd9Sstevel@tonic-gate {
19297c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp;
19300dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
19310dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 	if (oldcp) {
19350dfe541eSEvan Layton 		rw_enter(&nsrv4->rfs4_findclient_lock, RW_WRITER);
1936d216dff5SRobert Mastors 		rfs4_dbe_hide(oldcp->rc_dbe);
19377c478bd9Sstevel@tonic-gate 	} else {
19380dfe541eSEvan Layton 		rw_enter(&nsrv4->rfs4_findclient_lock, RW_READER);
19397c478bd9Sstevel@tonic-gate 	}
19407c478bd9Sstevel@tonic-gate 
19410dfe541eSEvan Layton 	cp = (rfs4_client_t *)rfs4_dbsearch(nsrv4->rfs4_nfsclnt_idx, client,
1942ed57cab9Srg 	    create, (void *)client, RFS4_DBS_VALID);
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	if (oldcp)
1945d216dff5SRobert Mastors 		rfs4_dbe_unhide(oldcp->rc_dbe);
19467c478bd9Sstevel@tonic-gate 
19470dfe541eSEvan Layton 	rw_exit(&nsrv4->rfs4_findclient_lock);
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 	return (cp);
19507c478bd9Sstevel@tonic-gate }
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate rfs4_client_t *
rfs4_findclient_by_id(clientid4 clientid,bool_t find_unconfirmed)19537c478bd9Sstevel@tonic-gate rfs4_findclient_by_id(clientid4 clientid, bool_t find_unconfirmed)
19547c478bd9Sstevel@tonic-gate {
19557c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp;
19567c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
19577c478bd9Sstevel@tonic-gate 	cid *cidp = (cid *)&clientid;
19580dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 	/* If we're a cluster and the nodeid isn't right, short-circuit */
19617c478bd9Sstevel@tonic-gate 	if (cluster_bootflags & CLUSTER_BOOTED && foreign_clientid(cidp))
19627c478bd9Sstevel@tonic-gate 		return (NULL);
19637c478bd9Sstevel@tonic-gate 
19640dfe541eSEvan Layton 	rw_enter(&nsrv4->rfs4_findclient_lock, RW_READER);
19657c478bd9Sstevel@tonic-gate 
19660dfe541eSEvan Layton 	cp = (rfs4_client_t *)rfs4_dbsearch(nsrv4->rfs4_clientid_idx, &clientid,
1967ed57cab9Srg 	    &create, NULL, RFS4_DBS_VALID);
19687c478bd9Sstevel@tonic-gate 
19690dfe541eSEvan Layton 	rw_exit(&nsrv4->rfs4_findclient_lock);
19707c478bd9Sstevel@tonic-gate 
1971d216dff5SRobert Mastors 	if (cp && cp->rc_need_confirm && find_unconfirmed == FALSE) {
19727c478bd9Sstevel@tonic-gate 		rfs4_client_rele(cp);
19737c478bd9Sstevel@tonic-gate 		return (NULL);
19747c478bd9Sstevel@tonic-gate 	} else {
19757c478bd9Sstevel@tonic-gate 		return (cp);
19767c478bd9Sstevel@tonic-gate 	}
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate 
19792f172c55SRobert Thurlow static uint32_t
clntip_hash(void * key)19802f172c55SRobert Thurlow clntip_hash(void *key)
19812f172c55SRobert Thurlow {
19822f172c55SRobert Thurlow 	struct sockaddr *addr = key;
19832f172c55SRobert Thurlow 	int i, len = 0;
19842f172c55SRobert Thurlow 	uint32_t hash = 0;
1985fab83d6aSRobert Thurlow 	char *ptr;
1986fab83d6aSRobert Thurlow 
1987fab83d6aSRobert Thurlow 	if (addr->sa_family == AF_INET) {
1988fab83d6aSRobert Thurlow 		struct sockaddr_in *a = (struct sockaddr_in *)addr;
1989fab83d6aSRobert Thurlow 		len = sizeof (struct in_addr);
1990fab83d6aSRobert Thurlow 		ptr = (char *)&a->sin_addr;
1991fab83d6aSRobert Thurlow 	} else if (addr->sa_family == AF_INET6) {
1992fab83d6aSRobert Thurlow 		struct sockaddr_in6 *a = (struct sockaddr_in6 *)addr;
1993fab83d6aSRobert Thurlow 		len = sizeof (struct in6_addr);
1994fab83d6aSRobert Thurlow 		ptr = (char *)&a->sin6_addr;
1995fab83d6aSRobert Thurlow 	} else
1996fab83d6aSRobert Thurlow 		return (0);
19972f172c55SRobert Thurlow 
19982f172c55SRobert Thurlow 	for (i = 0; i < len; i++) {
19992f172c55SRobert Thurlow 		hash <<= 1;
2000fab83d6aSRobert Thurlow 		hash += (uint_t)ptr[i];
20012f172c55SRobert Thurlow 	}
20022f172c55SRobert Thurlow 	return (hash);
20032f172c55SRobert Thurlow }
20042f172c55SRobert Thurlow 
20052f172c55SRobert Thurlow static bool_t
clntip_compare(rfs4_entry_t entry,void * key)20062f172c55SRobert Thurlow clntip_compare(rfs4_entry_t entry, void *key)
20072f172c55SRobert Thurlow {
20082f172c55SRobert Thurlow 	rfs4_clntip_t *cp = (rfs4_clntip_t *)entry;
20092f172c55SRobert Thurlow 	struct sockaddr *addr = key;
20102f172c55SRobert Thurlow 	int len = 0;
2011fab83d6aSRobert Thurlow 	char *p1, *p2;
2012fab83d6aSRobert Thurlow 
2013fab83d6aSRobert Thurlow 	if (addr->sa_family == AF_INET) {
2014fab83d6aSRobert Thurlow 		struct sockaddr_in *a1 = (struct sockaddr_in *)&cp->ri_addr;
2015fab83d6aSRobert Thurlow 		struct sockaddr_in *a2 = (struct sockaddr_in *)addr;
2016fab83d6aSRobert Thurlow 		len = sizeof (struct in_addr);
2017fab83d6aSRobert Thurlow 		p1 = (char *)&a1->sin_addr;
2018fab83d6aSRobert Thurlow 		p2 = (char *)&a2->sin_addr;
2019fab83d6aSRobert Thurlow 	} else if (addr->sa_family == AF_INET6) {
2020fab83d6aSRobert Thurlow 		struct sockaddr_in6 *a1 = (struct sockaddr_in6 *)&cp->ri_addr;
2021fab83d6aSRobert Thurlow 		struct sockaddr_in6 *a2 = (struct sockaddr_in6 *)addr;
2022fab83d6aSRobert Thurlow 		len = sizeof (struct in6_addr);
2023fab83d6aSRobert Thurlow 		p1 = (char *)&a1->sin6_addr;
2024fab83d6aSRobert Thurlow 		p2 = (char *)&a2->sin6_addr;
2025fab83d6aSRobert Thurlow 	} else
20262f172c55SRobert Thurlow 		return (0);
20272f172c55SRobert Thurlow 
2028fab83d6aSRobert Thurlow 	return (bcmp(p1, p2, len) == 0);
20292f172c55SRobert Thurlow }
20302f172c55SRobert Thurlow 
20312f172c55SRobert Thurlow static void *
clntip_mkkey(rfs4_entry_t entry)20322f172c55SRobert Thurlow clntip_mkkey(rfs4_entry_t entry)
20332f172c55SRobert Thurlow {
20342f172c55SRobert Thurlow 	rfs4_clntip_t *cp = (rfs4_clntip_t *)entry;
20352f172c55SRobert Thurlow 
20362f172c55SRobert Thurlow 	return (&cp->ri_addr);
20372f172c55SRobert Thurlow }
20382f172c55SRobert Thurlow 
20392f172c55SRobert Thurlow static bool_t
rfs4_clntip_expiry(rfs4_entry_t u_entry)20402f172c55SRobert Thurlow rfs4_clntip_expiry(rfs4_entry_t u_entry)
20412f172c55SRobert Thurlow {
20422f172c55SRobert Thurlow 	rfs4_clntip_t *cp = (rfs4_clntip_t *)u_entry;
20432f172c55SRobert Thurlow 
20442f172c55SRobert Thurlow 	if (rfs4_dbe_is_invalid(cp->ri_dbe))
20452f172c55SRobert Thurlow 		return (TRUE);
20462f172c55SRobert Thurlow 	return (FALSE);
20472f172c55SRobert Thurlow }
20482f172c55SRobert Thurlow 
20492f172c55SRobert Thurlow /* ARGSUSED */
20502f172c55SRobert Thurlow static void
rfs4_clntip_destroy(rfs4_entry_t u_entry)20512f172c55SRobert Thurlow rfs4_clntip_destroy(rfs4_entry_t u_entry)
20522f172c55SRobert Thurlow {
20532f172c55SRobert Thurlow }
20542f172c55SRobert Thurlow 
20552f172c55SRobert Thurlow static bool_t
rfs4_clntip_create(rfs4_entry_t u_entry,void * arg)20562f172c55SRobert Thurlow rfs4_clntip_create(rfs4_entry_t u_entry, void *arg)
20572f172c55SRobert Thurlow {
20582f172c55SRobert Thurlow 	rfs4_clntip_t *cp = (rfs4_clntip_t *)u_entry;
20592f172c55SRobert Thurlow 	struct sockaddr *ca = (struct sockaddr *)arg;
20602f172c55SRobert Thurlow 
20612f172c55SRobert Thurlow 	/* Copy client's IP address */
20622f172c55SRobert Thurlow 	if (ca->sa_family == AF_INET)
20632f172c55SRobert Thurlow 		bcopy(ca, &cp->ri_addr, sizeof (struct sockaddr_in));
20642f172c55SRobert Thurlow 	else if (ca->sa_family == AF_INET6)
20652f172c55SRobert Thurlow 		bcopy(ca, &cp->ri_addr, sizeof (struct sockaddr_in6));
20662f172c55SRobert Thurlow 	else
20672f172c55SRobert Thurlow 		return (FALSE);
20682f172c55SRobert Thurlow 	cp->ri_no_referrals = 1;
20692f172c55SRobert Thurlow 
20702f172c55SRobert Thurlow 	return (TRUE);
20712f172c55SRobert Thurlow }
20722f172c55SRobert Thurlow 
20732f172c55SRobert Thurlow rfs4_clntip_t *
rfs4_find_clntip(struct sockaddr * addr,bool_t * create)20742f172c55SRobert Thurlow rfs4_find_clntip(struct sockaddr *addr, bool_t *create)
20752f172c55SRobert Thurlow {
20762f172c55SRobert Thurlow 	rfs4_clntip_t *cp;
20770dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
20782f172c55SRobert Thurlow 
20790dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
20802f172c55SRobert Thurlow 
20810dfe541eSEvan Layton 	rw_enter(&nsrv4->rfs4_findclient_lock, RW_READER);
20820dfe541eSEvan Layton 
20830dfe541eSEvan Layton 	cp = (rfs4_clntip_t *)rfs4_dbsearch(nsrv4->rfs4_clntip_idx, addr,
20842f172c55SRobert Thurlow 	    create, addr, RFS4_DBS_VALID);
20852f172c55SRobert Thurlow 
20860dfe541eSEvan Layton 	rw_exit(&nsrv4->rfs4_findclient_lock);
20872f172c55SRobert Thurlow 
20882f172c55SRobert Thurlow 	return (cp);
20892f172c55SRobert Thurlow }
20902f172c55SRobert Thurlow 
20912f172c55SRobert Thurlow void
rfs4_invalidate_clntip(struct sockaddr * addr)20922f172c55SRobert Thurlow rfs4_invalidate_clntip(struct sockaddr *addr)
20932f172c55SRobert Thurlow {
20942f172c55SRobert Thurlow 	rfs4_clntip_t *cp;
20952f172c55SRobert Thurlow 	bool_t create = FALSE;
20960dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
20972f172c55SRobert Thurlow 
20980dfe541eSEvan Layton 	rw_enter(&nsrv4->rfs4_findclient_lock, RW_READER);
20992f172c55SRobert Thurlow 
21000dfe541eSEvan Layton 	cp = (rfs4_clntip_t *)rfs4_dbsearch(nsrv4->rfs4_clntip_idx, addr,
21012f172c55SRobert Thurlow 	    &create, NULL, RFS4_DBS_VALID);
21022f172c55SRobert Thurlow 	if (cp == NULL) {
21030dfe541eSEvan Layton 		rw_exit(&nsrv4->rfs4_findclient_lock);
21042f172c55SRobert Thurlow 		return;
21052f172c55SRobert Thurlow 	}
21062f172c55SRobert Thurlow 	rfs4_dbe_invalidate(cp->ri_dbe);
21072f172c55SRobert Thurlow 	rfs4_dbe_rele(cp->ri_dbe);
21082f172c55SRobert Thurlow 
21090dfe541eSEvan Layton 	rw_exit(&nsrv4->rfs4_findclient_lock);
21102f172c55SRobert Thurlow }
21112f172c55SRobert Thurlow 
21127c478bd9Sstevel@tonic-gate bool_t
rfs4_lease_expired(rfs4_client_t * cp)21137c478bd9Sstevel@tonic-gate rfs4_lease_expired(rfs4_client_t *cp)
21147c478bd9Sstevel@tonic-gate {
21157c478bd9Sstevel@tonic-gate 	bool_t rc;
21167c478bd9Sstevel@tonic-gate 
2117d216dff5SRobert Mastors 	rfs4_dbe_lock(cp->rc_dbe);
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	/*
21207c478bd9Sstevel@tonic-gate 	 * If the admin has executed clear_locks for this
21217c478bd9Sstevel@tonic-gate 	 * client id, force expire will be set, so no need
21227c478bd9Sstevel@tonic-gate 	 * to calculate anything because it's "outa here".
21237c478bd9Sstevel@tonic-gate 	 */
2124d216dff5SRobert Mastors 	if (cp->rc_forced_expire) {
21257c478bd9Sstevel@tonic-gate 		rc = TRUE;
21267c478bd9Sstevel@tonic-gate 	} else {
2127d216dff5SRobert Mastors 		rc = (gethrestime_sec() - cp->rc_last_access > rfs4_lease_time);
21287c478bd9Sstevel@tonic-gate 	}
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	/*
21317c478bd9Sstevel@tonic-gate 	 * If the lease has expired we will also want
21327c478bd9Sstevel@tonic-gate 	 * to remove any stable storage state data. So
21337c478bd9Sstevel@tonic-gate 	 * mark the client id accordingly.
21347c478bd9Sstevel@tonic-gate 	 */
2135d216dff5SRobert Mastors 	if (!cp->rc_ss_remove)
2136d216dff5SRobert Mastors 		cp->rc_ss_remove = (rc == TRUE);
21377c478bd9Sstevel@tonic-gate 
2138d216dff5SRobert Mastors 	rfs4_dbe_unlock(cp->rc_dbe);
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	return (rc);
21417c478bd9Sstevel@tonic-gate }
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate void
rfs4_update_lease(rfs4_client_t * cp)21447c478bd9Sstevel@tonic-gate rfs4_update_lease(rfs4_client_t *cp)
21457c478bd9Sstevel@tonic-gate {
2146d216dff5SRobert Mastors 	rfs4_dbe_lock(cp->rc_dbe);
2147d216dff5SRobert Mastors 	if (!cp->rc_forced_expire)
2148d216dff5SRobert Mastors 		cp->rc_last_access = gethrestime_sec();
2149d216dff5SRobert Mastors 	rfs4_dbe_unlock(cp->rc_dbe);
21507c478bd9Sstevel@tonic-gate }
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate static bool_t
EQOPENOWNER(open_owner4 * a,open_owner4 * b)21547c478bd9Sstevel@tonic-gate EQOPENOWNER(open_owner4 *a, open_owner4 *b)
21557c478bd9Sstevel@tonic-gate {
21567c478bd9Sstevel@tonic-gate 	bool_t rc;
21577c478bd9Sstevel@tonic-gate 
21587c478bd9Sstevel@tonic-gate 	if (a->clientid != b->clientid)
21597c478bd9Sstevel@tonic-gate 		return (FALSE);
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 	if (a->owner_len != b->owner_len)
21627c478bd9Sstevel@tonic-gate 		return (FALSE);
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	rc = (bcmp(a->owner_val, b->owner_val, a->owner_len) == 0);
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 	return (rc);
21677c478bd9Sstevel@tonic-gate }
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate static uint_t
openowner_hash(void * key)21707c478bd9Sstevel@tonic-gate openowner_hash(void *key)
21717c478bd9Sstevel@tonic-gate {
21727c478bd9Sstevel@tonic-gate 	int i;
21737c478bd9Sstevel@tonic-gate 	open_owner4 *openowner = key;
21747c478bd9Sstevel@tonic-gate 	uint_t hash = 0;
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 	for (i = 0; i < openowner->owner_len; i++) {
21777c478bd9Sstevel@tonic-gate 		hash <<= 4;
21787c478bd9Sstevel@tonic-gate 		hash += (uint_t)openowner->owner_val[i];
21797c478bd9Sstevel@tonic-gate 	}
21807c478bd9Sstevel@tonic-gate 	hash += (uint_t)openowner->clientid;
21817c478bd9Sstevel@tonic-gate 	hash |= (openowner->clientid >> 32);
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	return (hash);
21847c478bd9Sstevel@tonic-gate }
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate static bool_t
openowner_compare(rfs4_entry_t u_entry,void * key)21877c478bd9Sstevel@tonic-gate openowner_compare(rfs4_entry_t u_entry, void *key)
21887c478bd9Sstevel@tonic-gate {
2189d216dff5SRobert Mastors 	rfs4_openowner_t *oo = (rfs4_openowner_t *)u_entry;
21907c478bd9Sstevel@tonic-gate 	open_owner4 *arg = key;
21917c478bd9Sstevel@tonic-gate 
2192d216dff5SRobert Mastors 	return (EQOPENOWNER(&oo->ro_owner, arg));
21937c478bd9Sstevel@tonic-gate }
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate void *
openowner_mkkey(rfs4_entry_t u_entry)21967c478bd9Sstevel@tonic-gate openowner_mkkey(rfs4_entry_t u_entry)
21977c478bd9Sstevel@tonic-gate {
2198d216dff5SRobert Mastors 	rfs4_openowner_t *oo = (rfs4_openowner_t *)u_entry;
21997c478bd9Sstevel@tonic-gate 
2200d216dff5SRobert Mastors 	return (&oo->ro_owner);
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate 
2203afb25078SVitaliy Gusev /* ARGSUSED */
22047c478bd9Sstevel@tonic-gate static bool_t
rfs4_openowner_expiry(rfs4_entry_t u_entry)22057c478bd9Sstevel@tonic-gate rfs4_openowner_expiry(rfs4_entry_t u_entry)
22067c478bd9Sstevel@tonic-gate {
2207afb25078SVitaliy Gusev 	/* openstateid held us and did all needed delay */
2208afb25078SVitaliy Gusev 	return (TRUE);
22097c478bd9Sstevel@tonic-gate }
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate static void
rfs4_openowner_destroy(rfs4_entry_t u_entry)22127c478bd9Sstevel@tonic-gate rfs4_openowner_destroy(rfs4_entry_t u_entry)
22137c478bd9Sstevel@tonic-gate {
2214d216dff5SRobert Mastors 	rfs4_openowner_t *oo = (rfs4_openowner_t *)u_entry;
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	/* Remove open owner from client's lists of open owners */
2217d216dff5SRobert Mastors 	rfs4_dbe_lock(oo->ro_client->rc_dbe);
2218d216dff5SRobert Mastors 	list_remove(&oo->ro_client->rc_openownerlist, oo);
2219d216dff5SRobert Mastors 	rfs4_dbe_unlock(oo->ro_client->rc_dbe);
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	/* One less reference to the client */
2222d216dff5SRobert Mastors 	rfs4_client_rele(oo->ro_client);
2223d216dff5SRobert Mastors 	oo->ro_client = NULL;
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	/* Free the last reply for this lock owner */
2226d216dff5SRobert Mastors 	rfs4_free_reply(&oo->ro_reply);
22277c478bd9Sstevel@tonic-gate 
2228d216dff5SRobert Mastors 	if (oo->ro_reply_fh.nfs_fh4_val) {
2229d216dff5SRobert Mastors 		kmem_free(oo->ro_reply_fh.nfs_fh4_val,
2230d216dff5SRobert Mastors 		    oo->ro_reply_fh.nfs_fh4_len);
2231d216dff5SRobert Mastors 		oo->ro_reply_fh.nfs_fh4_val = NULL;
2232d216dff5SRobert Mastors 		oo->ro_reply_fh.nfs_fh4_len = 0;
22337c478bd9Sstevel@tonic-gate 	}
22347c478bd9Sstevel@tonic-gate 
2235d216dff5SRobert Mastors 	rfs4_sw_destroy(&oo->ro_sw);
2236d216dff5SRobert Mastors 	list_destroy(&oo->ro_statelist);
2237d216dff5SRobert Mastors 
22387c478bd9Sstevel@tonic-gate 	/* Free the lock owner id */
2239d216dff5SRobert Mastors 	kmem_free(oo->ro_owner.owner_val, oo->ro_owner.owner_len);
22407c478bd9Sstevel@tonic-gate }
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate void
rfs4_openowner_rele(rfs4_openowner_t * oo)2243d216dff5SRobert Mastors rfs4_openowner_rele(rfs4_openowner_t *oo)
22447c478bd9Sstevel@tonic-gate {
2245d216dff5SRobert Mastors 	rfs4_dbe_rele(oo->ro_dbe);
22467c478bd9Sstevel@tonic-gate }
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate static bool_t
rfs4_openowner_create(rfs4_entry_t u_entry,void * arg)22497c478bd9Sstevel@tonic-gate rfs4_openowner_create(rfs4_entry_t u_entry, void *arg)
22507c478bd9Sstevel@tonic-gate {
2251d216dff5SRobert Mastors 	rfs4_openowner_t *oo = (rfs4_openowner_t *)u_entry;
22527c478bd9Sstevel@tonic-gate 	rfs4_openowner_t *argp = (rfs4_openowner_t *)arg;
2253d216dff5SRobert Mastors 	open_owner4 *openowner = &argp->ro_owner;
2254d216dff5SRobert Mastors 	seqid4 seqid = argp->ro_open_seqid;
22557c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp;
22567c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
22570dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
22587c478bd9Sstevel@tonic-gate 
22590dfe541eSEvan Layton 	rw_enter(&nsrv4->rfs4_findclient_lock, RW_READER);
22607c478bd9Sstevel@tonic-gate 
22610dfe541eSEvan Layton 	cp = (rfs4_client_t *)rfs4_dbsearch(nsrv4->rfs4_clientid_idx,
2262ed57cab9Srg 	    &openowner->clientid,
2263ed57cab9Srg 	    &create, NULL, RFS4_DBS_VALID);
22647c478bd9Sstevel@tonic-gate 
22650dfe541eSEvan Layton 	rw_exit(&nsrv4->rfs4_findclient_lock);
22667c478bd9Sstevel@tonic-gate 
22677c478bd9Sstevel@tonic-gate 	if (cp == NULL)
22687c478bd9Sstevel@tonic-gate 		return (FALSE);
22697c478bd9Sstevel@tonic-gate 
2270d216dff5SRobert Mastors 	oo->ro_reply_fh.nfs_fh4_len = 0;
2271d216dff5SRobert Mastors 	oo->ro_reply_fh.nfs_fh4_val = NULL;
22727c478bd9Sstevel@tonic-gate 
2273d216dff5SRobert Mastors 	oo->ro_owner.clientid = openowner->clientid;
2274d216dff5SRobert Mastors 	oo->ro_owner.owner_val =
2275ed57cab9Srg 	    kmem_alloc(openowner->owner_len, KM_SLEEP);
2276ed57cab9Srg 
22777c478bd9Sstevel@tonic-gate 	bcopy(openowner->owner_val,
2278d216dff5SRobert Mastors 	    oo->ro_owner.owner_val, openowner->owner_len);
22797c478bd9Sstevel@tonic-gate 
2280d216dff5SRobert Mastors 	oo->ro_owner.owner_len = openowner->owner_len;
22817c478bd9Sstevel@tonic-gate 
2282d216dff5SRobert Mastors 	oo->ro_need_confirm = TRUE;
22837c478bd9Sstevel@tonic-gate 
2284d216dff5SRobert Mastors 	rfs4_sw_init(&oo->ro_sw);
22857c478bd9Sstevel@tonic-gate 
2286d216dff5SRobert Mastors 	oo->ro_open_seqid = seqid;
2287d216dff5SRobert Mastors 	bzero(&oo->ro_reply, sizeof (nfs_resop4));
2288d216dff5SRobert Mastors 	oo->ro_client = cp;
22897c478bd9Sstevel@tonic-gate 
2290d216dff5SRobert Mastors 	list_create(&oo->ro_statelist, sizeof (rfs4_state_t),
2291d216dff5SRobert Mastors 	    offsetof(rfs4_state_t, rs_node));
22927c478bd9Sstevel@tonic-gate 
2293d216dff5SRobert Mastors 	/* Insert openowner into client's open owner list */
2294d216dff5SRobert Mastors 	rfs4_dbe_lock(cp->rc_dbe);
2295d216dff5SRobert Mastors 	list_insert_tail(&cp->rc_openownerlist, oo);
2296d216dff5SRobert Mastors 	rfs4_dbe_unlock(cp->rc_dbe);
22977c478bd9Sstevel@tonic-gate 
22987c478bd9Sstevel@tonic-gate 	return (TRUE);
22997c478bd9Sstevel@tonic-gate }
23007c478bd9Sstevel@tonic-gate 
23017c478bd9Sstevel@tonic-gate rfs4_openowner_t *
rfs4_findopenowner(open_owner4 * openowner,bool_t * create,seqid4 seqid)23027c478bd9Sstevel@tonic-gate rfs4_findopenowner(open_owner4 *openowner, bool_t *create, seqid4 seqid)
23037c478bd9Sstevel@tonic-gate {
2304d216dff5SRobert Mastors 	rfs4_openowner_t *oo;
23057c478bd9Sstevel@tonic-gate 	rfs4_openowner_t arg;
23060dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
23077c478bd9Sstevel@tonic-gate 
2308d216dff5SRobert Mastors 	arg.ro_owner = *openowner;
2309d216dff5SRobert Mastors 	arg.ro_open_seqid = seqid;
23100dfe541eSEvan Layton 	/* CSTYLED */
23110dfe541eSEvan Layton 	oo = (rfs4_openowner_t *)rfs4_dbsearch(nsrv4->rfs4_openowner_idx, openowner,
2312ed57cab9Srg 	    create, &arg, RFS4_DBS_VALID);
23137c478bd9Sstevel@tonic-gate 
2314d216dff5SRobert Mastors 	return (oo);
23157c478bd9Sstevel@tonic-gate }
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate void
rfs4_update_open_sequence(rfs4_openowner_t * oo)2318d216dff5SRobert Mastors rfs4_update_open_sequence(rfs4_openowner_t *oo)
23197c478bd9Sstevel@tonic-gate {
23207c478bd9Sstevel@tonic-gate 
2321d216dff5SRobert Mastors 	rfs4_dbe_lock(oo->ro_dbe);
23227c478bd9Sstevel@tonic-gate 
2323d216dff5SRobert Mastors 	oo->ro_open_seqid++;
23247c478bd9Sstevel@tonic-gate 
2325d216dff5SRobert Mastors 	rfs4_dbe_unlock(oo->ro_dbe);
23267c478bd9Sstevel@tonic-gate }
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate void
rfs4_update_open_resp(rfs4_openowner_t * oo,nfs_resop4 * resp,nfs_fh4 * fh)2329d216dff5SRobert Mastors rfs4_update_open_resp(rfs4_openowner_t *oo, nfs_resop4 *resp, nfs_fh4 *fh)
23307c478bd9Sstevel@tonic-gate {
23317c478bd9Sstevel@tonic-gate 
2332d216dff5SRobert Mastors 	rfs4_dbe_lock(oo->ro_dbe);
23337c478bd9Sstevel@tonic-gate 
2334d216dff5SRobert Mastors 	rfs4_free_reply(&oo->ro_reply);
23357c478bd9Sstevel@tonic-gate 
2336d216dff5SRobert Mastors 	rfs4_copy_reply(&oo->ro_reply, resp);
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	/* Save the filehandle if provided and free if not used */
23397c478bd9Sstevel@tonic-gate 	if (resp->nfs_resop4_u.opopen.status == NFS4_OK &&
23407c478bd9Sstevel@tonic-gate 	    fh && fh->nfs_fh4_len) {
2341d216dff5SRobert Mastors 		if (oo->ro_reply_fh.nfs_fh4_val == NULL)
2342d216dff5SRobert Mastors 			oo->ro_reply_fh.nfs_fh4_val =
2343ed57cab9Srg 			    kmem_alloc(fh->nfs_fh4_len, KM_SLEEP);
2344d216dff5SRobert Mastors 		nfs_fh4_copy(fh, &oo->ro_reply_fh);
23457c478bd9Sstevel@tonic-gate 	} else {
2346d216dff5SRobert Mastors 		if (oo->ro_reply_fh.nfs_fh4_val) {
2347d216dff5SRobert Mastors 			kmem_free(oo->ro_reply_fh.nfs_fh4_val,
2348d216dff5SRobert Mastors 			    oo->ro_reply_fh.nfs_fh4_len);
2349d216dff5SRobert Mastors 			oo->ro_reply_fh.nfs_fh4_val = NULL;
2350d216dff5SRobert Mastors 			oo->ro_reply_fh.nfs_fh4_len = 0;
23517c478bd9Sstevel@tonic-gate 		}
23527c478bd9Sstevel@tonic-gate 	}
23537c478bd9Sstevel@tonic-gate 
2354d216dff5SRobert Mastors 	rfs4_dbe_unlock(oo->ro_dbe);
23557c478bd9Sstevel@tonic-gate }
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate static bool_t
lockowner_compare(rfs4_entry_t u_entry,void * key)23587c478bd9Sstevel@tonic-gate lockowner_compare(rfs4_entry_t u_entry, void *key)
23597c478bd9Sstevel@tonic-gate {
23607c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo = (rfs4_lockowner_t *)u_entry;
23617c478bd9Sstevel@tonic-gate 	lock_owner4 *b = (lock_owner4 *)key;
23627c478bd9Sstevel@tonic-gate 
2363d216dff5SRobert Mastors 	if (lo->rl_owner.clientid != b->clientid)
23647c478bd9Sstevel@tonic-gate 		return (FALSE);
23657c478bd9Sstevel@tonic-gate 
2366d216dff5SRobert Mastors 	if (lo->rl_owner.owner_len != b->owner_len)
23677c478bd9Sstevel@tonic-gate 		return (FALSE);
23687c478bd9Sstevel@tonic-gate 
2369d216dff5SRobert Mastors 	return (bcmp(lo->rl_owner.owner_val, b->owner_val,
2370d216dff5SRobert Mastors 	    lo->rl_owner.owner_len) == 0);
23717c478bd9Sstevel@tonic-gate }
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate void *
lockowner_mkkey(rfs4_entry_t u_entry)23747c478bd9Sstevel@tonic-gate lockowner_mkkey(rfs4_entry_t u_entry)
23757c478bd9Sstevel@tonic-gate {
23767c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo = (rfs4_lockowner_t *)u_entry;
23777c478bd9Sstevel@tonic-gate 
2378d216dff5SRobert Mastors 	return (&lo->rl_owner);
23797c478bd9Sstevel@tonic-gate }
23807c478bd9Sstevel@tonic-gate 
23817c478bd9Sstevel@tonic-gate static uint32_t
lockowner_hash(void * key)23827c478bd9Sstevel@tonic-gate lockowner_hash(void *key)
23837c478bd9Sstevel@tonic-gate {
23847c478bd9Sstevel@tonic-gate 	int i;
23857c478bd9Sstevel@tonic-gate 	lock_owner4 *lockowner = key;
23867c478bd9Sstevel@tonic-gate 	uint_t hash = 0;
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate 	for (i = 0; i < lockowner->owner_len; i++) {
23897c478bd9Sstevel@tonic-gate 		hash <<= 4;
23907c478bd9Sstevel@tonic-gate 		hash += (uint_t)lockowner->owner_val[i];
23917c478bd9Sstevel@tonic-gate 	}
23927c478bd9Sstevel@tonic-gate 	hash += (uint_t)lockowner->clientid;
23937c478bd9Sstevel@tonic-gate 	hash |= (lockowner->clientid >> 32);
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 	return (hash);
23967c478bd9Sstevel@tonic-gate }
23977c478bd9Sstevel@tonic-gate 
23987c478bd9Sstevel@tonic-gate static uint32_t
pid_hash(void * key)23997c478bd9Sstevel@tonic-gate pid_hash(void *key)
24007c478bd9Sstevel@tonic-gate {
24017c478bd9Sstevel@tonic-gate 	return ((uint32_t)(uintptr_t)key);
24027c478bd9Sstevel@tonic-gate }
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate static void *
pid_mkkey(rfs4_entry_t u_entry)24057c478bd9Sstevel@tonic-gate pid_mkkey(rfs4_entry_t u_entry)
24067c478bd9Sstevel@tonic-gate {
24077c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo = (rfs4_lockowner_t *)u_entry;
24087c478bd9Sstevel@tonic-gate 
2409d216dff5SRobert Mastors 	return ((void *)(uintptr_t)lo->rl_pid);
24107c478bd9Sstevel@tonic-gate }
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate static bool_t
pid_compare(rfs4_entry_t u_entry,void * key)24137c478bd9Sstevel@tonic-gate pid_compare(rfs4_entry_t u_entry, void *key)
24147c478bd9Sstevel@tonic-gate {
24157c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo = (rfs4_lockowner_t *)u_entry;
24167c478bd9Sstevel@tonic-gate 
2417d216dff5SRobert Mastors 	return (lo->rl_pid == (pid_t)(uintptr_t)key);
24187c478bd9Sstevel@tonic-gate }
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate static void
rfs4_lockowner_destroy(rfs4_entry_t u_entry)24217c478bd9Sstevel@tonic-gate rfs4_lockowner_destroy(rfs4_entry_t u_entry)
24227c478bd9Sstevel@tonic-gate {
24237c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo = (rfs4_lockowner_t *)u_entry;
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	/* Free the lock owner id */
2426d216dff5SRobert Mastors 	kmem_free(lo->rl_owner.owner_val, lo->rl_owner.owner_len);
2427d216dff5SRobert Mastors 	rfs4_client_rele(lo->rl_client);
24287c478bd9Sstevel@tonic-gate }
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate void
rfs4_lockowner_rele(rfs4_lockowner_t * lo)24317c478bd9Sstevel@tonic-gate rfs4_lockowner_rele(rfs4_lockowner_t *lo)
24327c478bd9Sstevel@tonic-gate {
2433d216dff5SRobert Mastors 	rfs4_dbe_rele(lo->rl_dbe);
24347c478bd9Sstevel@tonic-gate }
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate /* ARGSUSED */
24377c478bd9Sstevel@tonic-gate static bool_t
rfs4_lockowner_expiry(rfs4_entry_t u_entry)24387c478bd9Sstevel@tonic-gate rfs4_lockowner_expiry(rfs4_entry_t u_entry)
24397c478bd9Sstevel@tonic-gate {
24407c478bd9Sstevel@tonic-gate 	/*
24417c478bd9Sstevel@tonic-gate 	 * Since expiry is called with no other references on
24427c478bd9Sstevel@tonic-gate 	 * this struct, go ahead and have it removed.
24437c478bd9Sstevel@tonic-gate 	 */
24447c478bd9Sstevel@tonic-gate 	return (TRUE);
24457c478bd9Sstevel@tonic-gate }
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate static bool_t
rfs4_lockowner_create(rfs4_entry_t u_entry,void * arg)24487c478bd9Sstevel@tonic-gate rfs4_lockowner_create(rfs4_entry_t u_entry, void *arg)
24497c478bd9Sstevel@tonic-gate {
24507c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo = (rfs4_lockowner_t *)u_entry;
24517c478bd9Sstevel@tonic-gate 	lock_owner4 *lockowner = (lock_owner4 *)arg;
24527c478bd9Sstevel@tonic-gate 	rfs4_client_t *cp;
24537c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
24540dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
24557c478bd9Sstevel@tonic-gate 
24560dfe541eSEvan Layton 	rw_enter(&nsrv4->rfs4_findclient_lock, RW_READER);
24577c478bd9Sstevel@tonic-gate 
24580dfe541eSEvan Layton 	cp = (rfs4_client_t *)rfs4_dbsearch(nsrv4->rfs4_clientid_idx,
2459ed57cab9Srg 	    &lockowner->clientid,
2460ed57cab9Srg 	    &create, NULL, RFS4_DBS_VALID);
24617c478bd9Sstevel@tonic-gate 
24620dfe541eSEvan Layton 	rw_exit(&nsrv4->rfs4_findclient_lock);
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 	if (cp == NULL)
24657c478bd9Sstevel@tonic-gate 		return (FALSE);
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	/* Reference client */
2468d216dff5SRobert Mastors 	lo->rl_client = cp;
2469d216dff5SRobert Mastors 	lo->rl_owner.clientid = lockowner->clientid;
2470d216dff5SRobert Mastors 	lo->rl_owner.owner_val = kmem_alloc(lockowner->owner_len, KM_SLEEP);
2471d216dff5SRobert Mastors 	bcopy(lockowner->owner_val, lo->rl_owner.owner_val,
2472d216dff5SRobert Mastors 	    lockowner->owner_len);
2473d216dff5SRobert Mastors 	lo->rl_owner.owner_len = lockowner->owner_len;
2474d216dff5SRobert Mastors 	lo->rl_pid = rfs4_dbe_getid(lo->rl_dbe);
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	return (TRUE);
24777c478bd9Sstevel@tonic-gate }
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate rfs4_lockowner_t *
rfs4_findlockowner(lock_owner4 * lockowner,bool_t * create)24807c478bd9Sstevel@tonic-gate rfs4_findlockowner(lock_owner4 *lockowner, bool_t *create)
24817c478bd9Sstevel@tonic-gate {
24827c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo;
24830dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
24847c478bd9Sstevel@tonic-gate 
24850dfe541eSEvan Layton 	/* CSTYLED */
24860dfe541eSEvan Layton 	lo = (rfs4_lockowner_t *)rfs4_dbsearch(nsrv4->rfs4_lockowner_idx, lockowner,
2487ed57cab9Srg 	    create, lockowner, RFS4_DBS_VALID);
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 	return (lo);
24907c478bd9Sstevel@tonic-gate }
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate rfs4_lockowner_t *
rfs4_findlockowner_by_pid(pid_t pid)24937c478bd9Sstevel@tonic-gate rfs4_findlockowner_by_pid(pid_t pid)
24947c478bd9Sstevel@tonic-gate {
24957c478bd9Sstevel@tonic-gate 	rfs4_lockowner_t *lo;
24967c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
24970dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
24987c478bd9Sstevel@tonic-gate 
24990dfe541eSEvan Layton 	lo = (rfs4_lockowner_t *)rfs4_dbsearch(nsrv4->rfs4_lockowner_pid_idx,
2500ed57cab9Srg 	    (void *)(uintptr_t)pid, &create, NULL, RFS4_DBS_VALID);
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	return (lo);
25037c478bd9Sstevel@tonic-gate }
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate static uint32_t
file_hash(void * key)25077c478bd9Sstevel@tonic-gate file_hash(void *key)
25087c478bd9Sstevel@tonic-gate {
25097c478bd9Sstevel@tonic-gate 	return (ADDRHASH(key));
25107c478bd9Sstevel@tonic-gate }
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate static void *
file_mkkey(rfs4_entry_t u_entry)25137c478bd9Sstevel@tonic-gate file_mkkey(rfs4_entry_t u_entry)
25147c478bd9Sstevel@tonic-gate {
25157c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp = (rfs4_file_t *)u_entry;
25167c478bd9Sstevel@tonic-gate 
2517d216dff5SRobert Mastors 	return (fp->rf_vp);
25187c478bd9Sstevel@tonic-gate }
25197c478bd9Sstevel@tonic-gate 
25207c478bd9Sstevel@tonic-gate static bool_t
file_compare(rfs4_entry_t u_entry,void * key)25217c478bd9Sstevel@tonic-gate file_compare(rfs4_entry_t u_entry, void *key)
25227c478bd9Sstevel@tonic-gate {
25237c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp = (rfs4_file_t *)u_entry;
25247c478bd9Sstevel@tonic-gate 
2525d216dff5SRobert Mastors 	return (fp->rf_vp == (vnode_t *)key);
25267c478bd9Sstevel@tonic-gate }
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate static void
rfs4_file_destroy(rfs4_entry_t u_entry)25297c478bd9Sstevel@tonic-gate rfs4_file_destroy(rfs4_entry_t u_entry)
25307c478bd9Sstevel@tonic-gate {
25317c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp = (rfs4_file_t *)u_entry;
25327c478bd9Sstevel@tonic-gate 
2533d216dff5SRobert Mastors 	list_destroy(&fp->rf_delegstatelist);
2534d216dff5SRobert Mastors 
2535d216dff5SRobert Mastors 	if (fp->rf_filehandle.nfs_fh4_val)
2536d216dff5SRobert Mastors 		kmem_free(fp->rf_filehandle.nfs_fh4_val,
2537d216dff5SRobert Mastors 		    fp->rf_filehandle.nfs_fh4_len);
2538d216dff5SRobert Mastors 	cv_destroy(fp->rf_dinfo.rd_recall_cv);
2539d216dff5SRobert Mastors 	if (fp->rf_vp) {
2540d216dff5SRobert Mastors 		vnode_t *vp = fp->rf_vp;
25411b300de9Sjwahlig 
2542d216dff5SRobert Mastors 		mutex_enter(&vp->v_vsd_lock);
25431b300de9Sjwahlig 		(void) vsd_set(vp, nfs4_srv_vkey, NULL);
2544d216dff5SRobert Mastors 		mutex_exit(&vp->v_vsd_lock);
25451b300de9Sjwahlig 		VN_RELE(vp);
2546d216dff5SRobert Mastors 		fp->rf_vp = NULL;
25477c478bd9Sstevel@tonic-gate 	}
2548d216dff5SRobert Mastors 	rw_destroy(&fp->rf_file_rwlock);
25497c478bd9Sstevel@tonic-gate }
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate /*
25527c478bd9Sstevel@tonic-gate  * Used to unlock the underlying dbe struct only
25537c478bd9Sstevel@tonic-gate  */
25547c478bd9Sstevel@tonic-gate void
rfs4_file_rele(rfs4_file_t * fp)25557c478bd9Sstevel@tonic-gate rfs4_file_rele(rfs4_file_t *fp)
25567c478bd9Sstevel@tonic-gate {
2557d216dff5SRobert Mastors 	rfs4_dbe_rele(fp->rf_dbe);
25587c478bd9Sstevel@tonic-gate }
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate typedef struct {
25617c478bd9Sstevel@tonic-gate     vnode_t *vp;
25627c478bd9Sstevel@tonic-gate     nfs_fh4 *fh;
25637c478bd9Sstevel@tonic-gate } rfs4_fcreate_arg;
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate static bool_t
rfs4_file_create(rfs4_entry_t u_entry,void * arg)25667c478bd9Sstevel@tonic-gate rfs4_file_create(rfs4_entry_t u_entry, void *arg)
25677c478bd9Sstevel@tonic-gate {
25687c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp = (rfs4_file_t *)u_entry;
25697c478bd9Sstevel@tonic-gate 	rfs4_fcreate_arg *ap = (rfs4_fcreate_arg *)arg;
25707c478bd9Sstevel@tonic-gate 	vnode_t *vp = ap->vp;
25717c478bd9Sstevel@tonic-gate 	nfs_fh4 *fh = ap->fh;
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
25747c478bd9Sstevel@tonic-gate 
2575d216dff5SRobert Mastors 	fp->rf_filehandle.nfs_fh4_len = 0;
2576d216dff5SRobert Mastors 	fp->rf_filehandle.nfs_fh4_val = NULL;
25777c478bd9Sstevel@tonic-gate 	ASSERT(fh && fh->nfs_fh4_len);
25787c478bd9Sstevel@tonic-gate 	if (fh && fh->nfs_fh4_len) {
2579d216dff5SRobert Mastors 		fp->rf_filehandle.nfs_fh4_val =
2580ed57cab9Srg 		    kmem_alloc(fh->nfs_fh4_len, KM_SLEEP);
2581d216dff5SRobert Mastors 		nfs_fh4_copy(fh, &fp->rf_filehandle);
25827c478bd9Sstevel@tonic-gate 	}
2583d216dff5SRobert Mastors 	fp->rf_vp = vp;
25847c478bd9Sstevel@tonic-gate 
2585d216dff5SRobert Mastors 	list_create(&fp->rf_delegstatelist, sizeof (rfs4_deleg_state_t),
2586d216dff5SRobert Mastors 	    offsetof(rfs4_deleg_state_t, rds_node));
25877c478bd9Sstevel@tonic-gate 
2588d216dff5SRobert Mastors 	fp->rf_share_deny = fp->rf_share_access = fp->rf_access_read = 0;
2589d216dff5SRobert Mastors 	fp->rf_access_write = fp->rf_deny_read = fp->rf_deny_write = 0;
25907c478bd9Sstevel@tonic-gate 
2591d216dff5SRobert Mastors 	mutex_init(fp->rf_dinfo.rd_recall_lock, NULL, MUTEX_DEFAULT, NULL);
2592d216dff5SRobert Mastors 	cv_init(fp->rf_dinfo.rd_recall_cv, NULL, CV_DEFAULT, NULL);
25937c478bd9Sstevel@tonic-gate 
2594d216dff5SRobert Mastors 	fp->rf_dinfo.rd_dtype = OPEN_DELEGATE_NONE;
25957c478bd9Sstevel@tonic-gate 
2596d216dff5SRobert Mastors 	rw_init(&fp->rf_file_rwlock, NULL, RW_DEFAULT, NULL);
25977c478bd9Sstevel@tonic-gate 
2598d216dff5SRobert Mastors 	mutex_enter(&vp->v_vsd_lock);
2599d216dff5SRobert Mastors 	VERIFY(vsd_set(vp, nfs4_srv_vkey, (void *)fp) == 0);
2600d216dff5SRobert Mastors 	mutex_exit(&vp->v_vsd_lock);
26011b300de9Sjwahlig 
26027c478bd9Sstevel@tonic-gate 	return (TRUE);
26037c478bd9Sstevel@tonic-gate }
26047c478bd9Sstevel@tonic-gate 
26057c478bd9Sstevel@tonic-gate rfs4_file_t *
rfs4_findfile(vnode_t * vp,nfs_fh4 * fh,bool_t * create)26067c478bd9Sstevel@tonic-gate rfs4_findfile(vnode_t *vp, nfs_fh4 *fh, bool_t *create)
26077c478bd9Sstevel@tonic-gate {
26087c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
26097c478bd9Sstevel@tonic-gate 	rfs4_fcreate_arg arg;
26100dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate 	arg.vp = vp;
26137c478bd9Sstevel@tonic-gate 	arg.fh = fh;
26147c478bd9Sstevel@tonic-gate 
26151b300de9Sjwahlig 	if (*create == TRUE)
26160dfe541eSEvan Layton 		/* CSTYLED */
26170dfe541eSEvan Layton 		fp = (rfs4_file_t *)rfs4_dbsearch(nsrv4->rfs4_file_idx, vp, create,
26181b300de9Sjwahlig 		    &arg, RFS4_DBS_VALID);
26191b300de9Sjwahlig 	else {
2620d216dff5SRobert Mastors 		mutex_enter(&vp->v_vsd_lock);
26211b300de9Sjwahlig 		fp = (rfs4_file_t *)vsd_get(vp, nfs4_srv_vkey);
26221b300de9Sjwahlig 		if (fp) {
2623d216dff5SRobert Mastors 			rfs4_dbe_lock(fp->rf_dbe);
2624d216dff5SRobert Mastors 			if (rfs4_dbe_is_invalid(fp->rf_dbe) ||
2625d216dff5SRobert Mastors 			    (rfs4_dbe_refcnt(fp->rf_dbe) == 0)) {
2626d216dff5SRobert Mastors 				rfs4_dbe_unlock(fp->rf_dbe);
26271b300de9Sjwahlig 				fp = NULL;
26281b300de9Sjwahlig 			} else {
2629d216dff5SRobert Mastors 				rfs4_dbe_hold(fp->rf_dbe);
2630d216dff5SRobert Mastors 				rfs4_dbe_unlock(fp->rf_dbe);
26311b300de9Sjwahlig 			}
26321b300de9Sjwahlig 		}
2633d216dff5SRobert Mastors 		mutex_exit(&vp->v_vsd_lock);
26341b300de9Sjwahlig 	}
26357c478bd9Sstevel@tonic-gate 	return (fp);
26367c478bd9Sstevel@tonic-gate }
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate /*
26397c478bd9Sstevel@tonic-gate  * Find a file in the db and once it is located, take the rw lock.
26407c478bd9Sstevel@tonic-gate  * Need to check the vnode pointer and if it does not exist (it was
26417c478bd9Sstevel@tonic-gate  * removed between the db location and check) redo the find.  This
26427c478bd9Sstevel@tonic-gate  * assumes that a file struct that has a NULL vnode pointer is marked
26437c478bd9Sstevel@tonic-gate  * at 'invalid' and will not be found in the db the second time
26447c478bd9Sstevel@tonic-gate  * around.
26457c478bd9Sstevel@tonic-gate  */
26467c478bd9Sstevel@tonic-gate rfs4_file_t *
rfs4_findfile_withlock(vnode_t * vp,nfs_fh4 * fh,bool_t * create)26477c478bd9Sstevel@tonic-gate rfs4_findfile_withlock(vnode_t *vp, nfs_fh4 *fh, bool_t *create)
26487c478bd9Sstevel@tonic-gate {
26497c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
26507c478bd9Sstevel@tonic-gate 	rfs4_fcreate_arg arg;
26517c478bd9Sstevel@tonic-gate 	bool_t screate = *create;
26520dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
26537c478bd9Sstevel@tonic-gate 
26541b300de9Sjwahlig 	if (screate == FALSE) {
2655d216dff5SRobert Mastors 		mutex_enter(&vp->v_vsd_lock);
26561b300de9Sjwahlig 		fp = (rfs4_file_t *)vsd_get(vp, nfs4_srv_vkey);
26571b300de9Sjwahlig 		if (fp) {
2658d216dff5SRobert Mastors 			rfs4_dbe_lock(fp->rf_dbe);
2659d216dff5SRobert Mastors 			if (rfs4_dbe_is_invalid(fp->rf_dbe) ||
2660d216dff5SRobert Mastors 			    (rfs4_dbe_refcnt(fp->rf_dbe) == 0)) {
2661d216dff5SRobert Mastors 				rfs4_dbe_unlock(fp->rf_dbe);
2662d216dff5SRobert Mastors 				mutex_exit(&vp->v_vsd_lock);
26631b300de9Sjwahlig 				fp = NULL;
26641b300de9Sjwahlig 			} else {
2665d216dff5SRobert Mastors 				rfs4_dbe_hold(fp->rf_dbe);
2666d216dff5SRobert Mastors 				rfs4_dbe_unlock(fp->rf_dbe);
2667d216dff5SRobert Mastors 				mutex_exit(&vp->v_vsd_lock);
2668d216dff5SRobert Mastors 				rw_enter(&fp->rf_file_rwlock, RW_WRITER);
2669d216dff5SRobert Mastors 				if (fp->rf_vp == NULL) {
2670d216dff5SRobert Mastors 					rw_exit(&fp->rf_file_rwlock);
2671a08f57bcSJames Wahlig 					rfs4_file_rele(fp);
2672a08f57bcSJames Wahlig 					fp = NULL;
2673a08f57bcSJames Wahlig 				}
26741b300de9Sjwahlig 			}
2675d216dff5SRobert Mastors 		} else {
2676d216dff5SRobert Mastors 			mutex_exit(&vp->v_vsd_lock);
26771b300de9Sjwahlig 		}
26781b300de9Sjwahlig 	} else {
26797c478bd9Sstevel@tonic-gate retry:
26801b300de9Sjwahlig 		arg.vp = vp;
26811b300de9Sjwahlig 		arg.fh = fh;
26821b300de9Sjwahlig 
26830dfe541eSEvan Layton 		fp = (rfs4_file_t *)rfs4_dbsearch(nsrv4->rfs4_file_idx, vp,
26840dfe541eSEvan Layton 		    create, &arg, RFS4_DBS_VALID);
26851b300de9Sjwahlig 		if (fp != NULL) {
2686d216dff5SRobert Mastors 			rw_enter(&fp->rf_file_rwlock, RW_WRITER);
2687d216dff5SRobert Mastors 			if (fp->rf_vp == NULL) {
2688d216dff5SRobert Mastors 				rw_exit(&fp->rf_file_rwlock);
26891b300de9Sjwahlig 				rfs4_file_rele(fp);
26901b300de9Sjwahlig 				*create = screate;
26911b300de9Sjwahlig 				goto retry;
26921b300de9Sjwahlig 			}
26937c478bd9Sstevel@tonic-gate 		}
26947c478bd9Sstevel@tonic-gate 	}
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate 	return (fp);
26977c478bd9Sstevel@tonic-gate }
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate static uint32_t
lo_state_hash(void * key)27007c478bd9Sstevel@tonic-gate lo_state_hash(void *key)
27017c478bd9Sstevel@tonic-gate {
27027c478bd9Sstevel@tonic-gate 	stateid_t *id = key;
27037c478bd9Sstevel@tonic-gate 
27047c478bd9Sstevel@tonic-gate 	return (id->bits.ident+id->bits.pid);
27057c478bd9Sstevel@tonic-gate }
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate static bool_t
lo_state_compare(rfs4_entry_t u_entry,void * key)27087c478bd9Sstevel@tonic-gate lo_state_compare(rfs4_entry_t u_entry, void *key)
27097c478bd9Sstevel@tonic-gate {
2710d216dff5SRobert Mastors 	rfs4_lo_state_t *lsp = (rfs4_lo_state_t *)u_entry;
27117c478bd9Sstevel@tonic-gate 	stateid_t *id = key;
27127c478bd9Sstevel@tonic-gate 	bool_t rc;
27137c478bd9Sstevel@tonic-gate 
2714d216dff5SRobert Mastors 	rc = (lsp->rls_lockid.bits.boottime == id->bits.boottime &&
2715d216dff5SRobert Mastors 	    lsp->rls_lockid.bits.type == id->bits.type &&
2716d216dff5SRobert Mastors 	    lsp->rls_lockid.bits.ident == id->bits.ident &&
2717d216dff5SRobert Mastors 	    lsp->rls_lockid.bits.pid == id->bits.pid);
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate 	return (rc);
27207c478bd9Sstevel@tonic-gate }
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate static void *
lo_state_mkkey(rfs4_entry_t u_entry)27237c478bd9Sstevel@tonic-gate lo_state_mkkey(rfs4_entry_t u_entry)
27247c478bd9Sstevel@tonic-gate {
27257c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp = (rfs4_lo_state_t *)u_entry;
27267c478bd9Sstevel@tonic-gate 
2727d216dff5SRobert Mastors 	return (&lsp->rls_lockid);
27287c478bd9Sstevel@tonic-gate }
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate static bool_t
rfs4_lo_state_expiry(rfs4_entry_t u_entry)27317c478bd9Sstevel@tonic-gate rfs4_lo_state_expiry(rfs4_entry_t u_entry)
27327c478bd9Sstevel@tonic-gate {
27337c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp = (rfs4_lo_state_t *)u_entry;
27347c478bd9Sstevel@tonic-gate 
2735d216dff5SRobert Mastors 	if (rfs4_dbe_is_invalid(lsp->rls_dbe))
27367c478bd9Sstevel@tonic-gate 		return (TRUE);
2737d216dff5SRobert Mastors 	if (lsp->rls_state->rs_closed)
27387c478bd9Sstevel@tonic-gate 		return (TRUE);
2739d216dff5SRobert Mastors 	return ((gethrestime_sec() -
2740d216dff5SRobert Mastors 	    lsp->rls_state->rs_owner->ro_client->rc_last_access
2741ed57cab9Srg 	    > rfs4_lease_time));
27427c478bd9Sstevel@tonic-gate }
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate static void
rfs4_lo_state_destroy(rfs4_entry_t u_entry)27457c478bd9Sstevel@tonic-gate rfs4_lo_state_destroy(rfs4_entry_t u_entry)
27467c478bd9Sstevel@tonic-gate {
27477c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp = (rfs4_lo_state_t *)u_entry;
27487c478bd9Sstevel@tonic-gate 
2749d216dff5SRobert Mastors 	rfs4_dbe_lock(lsp->rls_state->rs_dbe);
2750d216dff5SRobert Mastors 	list_remove(&lsp->rls_state->rs_lostatelist, lsp);
2751d216dff5SRobert Mastors 	rfs4_dbe_unlock(lsp->rls_state->rs_dbe);
2752d216dff5SRobert Mastors 
2753d216dff5SRobert Mastors 	rfs4_sw_destroy(&lsp->rls_sw);
27547c478bd9Sstevel@tonic-gate 
27557c478bd9Sstevel@tonic-gate 	/* Make sure to release the file locks */
2756d216dff5SRobert Mastors 	if (lsp->rls_locks_cleaned == FALSE) {
2757d216dff5SRobert Mastors 		lsp->rls_locks_cleaned = TRUE;
2758d216dff5SRobert Mastors 		if (lsp->rls_locker->rl_client->rc_sysidt != LM_NOSYSID) {
27597c478bd9Sstevel@tonic-gate 			/* Is the PxFS kernel module loaded? */
27607c478bd9Sstevel@tonic-gate 			if (lm_remove_file_locks != NULL) {
27617c478bd9Sstevel@tonic-gate 				int new_sysid;
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 				/* Encode the cluster nodeid in new sysid */
2764d216dff5SRobert Mastors 				new_sysid =
2765d216dff5SRobert Mastors 				    lsp->rls_locker->rl_client->rc_sysidt;
27667c478bd9Sstevel@tonic-gate 				lm_set_nlmid_flk(&new_sysid);
27677c478bd9Sstevel@tonic-gate 
27687c478bd9Sstevel@tonic-gate 				/*
27697c478bd9Sstevel@tonic-gate 				 * This PxFS routine removes file locks for a
27707c478bd9Sstevel@tonic-gate 				 * client over all nodes of a cluster.
27717c478bd9Sstevel@tonic-gate 				 */
2772ed57cab9Srg 				DTRACE_PROBE1(nfss_i_clust_rm_lck,
2773ed57cab9Srg 				    int, new_sysid);
27747c478bd9Sstevel@tonic-gate 				(*lm_remove_file_locks)(new_sysid);
27757c478bd9Sstevel@tonic-gate 			} else {
2776d216dff5SRobert Mastors 				(void) cleanlocks(
2777d216dff5SRobert Mastors 				    lsp->rls_state->rs_finfo->rf_vp,
2778d216dff5SRobert Mastors 				    lsp->rls_locker->rl_pid,
2779d216dff5SRobert Mastors 				    lsp->rls_locker->rl_client->rc_sysidt);
27807c478bd9Sstevel@tonic-gate 			}
27817c478bd9Sstevel@tonic-gate 		}
27827c478bd9Sstevel@tonic-gate 	}
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	/* Free the last reply for this state */
2785d216dff5SRobert Mastors 	rfs4_free_reply(&lsp->rls_reply);
27867c478bd9Sstevel@tonic-gate 
2787d216dff5SRobert Mastors 	rfs4_lockowner_rele(lsp->rls_locker);
2788d216dff5SRobert Mastors 	lsp->rls_locker = NULL;
27897c478bd9Sstevel@tonic-gate 
2790d216dff5SRobert Mastors 	rfs4_state_rele_nounlock(lsp->rls_state);
2791d216dff5SRobert Mastors 	lsp->rls_state = NULL;
27927c478bd9Sstevel@tonic-gate }
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate static bool_t
rfs4_lo_state_create(rfs4_entry_t u_entry,void * arg)27957c478bd9Sstevel@tonic-gate rfs4_lo_state_create(rfs4_entry_t u_entry, void *arg)
27967c478bd9Sstevel@tonic-gate {
27977c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp = (rfs4_lo_state_t *)u_entry;
27987c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *argp = (rfs4_lo_state_t *)arg;
2799d216dff5SRobert Mastors 	rfs4_lockowner_t *lo = argp->rls_locker;
2800d216dff5SRobert Mastors 	rfs4_state_t *sp = argp->rls_state;
28017c478bd9Sstevel@tonic-gate 
2802d216dff5SRobert Mastors 	lsp->rls_state = sp;
28037c478bd9Sstevel@tonic-gate 
2804d216dff5SRobert Mastors 	lsp->rls_lockid = sp->rs_stateid;
2805d216dff5SRobert Mastors 	lsp->rls_lockid.bits.type = LOCKID;
2806d216dff5SRobert Mastors 	lsp->rls_lockid.bits.chgseq = 0;
2807d216dff5SRobert Mastors 	lsp->rls_lockid.bits.pid = lo->rl_pid;
28087c478bd9Sstevel@tonic-gate 
2809d216dff5SRobert Mastors 	lsp->rls_locks_cleaned = FALSE;
2810d216dff5SRobert Mastors 	lsp->rls_lock_completed = FALSE;
28117c478bd9Sstevel@tonic-gate 
2812d216dff5SRobert Mastors 	rfs4_sw_init(&lsp->rls_sw);
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 	/* Attached the supplied lock owner */
2815d216dff5SRobert Mastors 	rfs4_dbe_hold(lo->rl_dbe);
2816d216dff5SRobert Mastors 	lsp->rls_locker = lo;
28177c478bd9Sstevel@tonic-gate 
2818d216dff5SRobert Mastors 	rfs4_dbe_lock(sp->rs_dbe);
2819d216dff5SRobert Mastors 	list_insert_tail(&sp->rs_lostatelist, lsp);
2820d216dff5SRobert Mastors 	rfs4_dbe_hold(sp->rs_dbe);
2821d216dff5SRobert Mastors 	rfs4_dbe_unlock(sp->rs_dbe);
28227c478bd9Sstevel@tonic-gate 
28237c478bd9Sstevel@tonic-gate 	return (TRUE);
28247c478bd9Sstevel@tonic-gate }
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate void
rfs4_lo_state_rele(rfs4_lo_state_t * lsp,bool_t unlock_fp)28277c478bd9Sstevel@tonic-gate rfs4_lo_state_rele(rfs4_lo_state_t *lsp, bool_t unlock_fp)
28287c478bd9Sstevel@tonic-gate {
28297c478bd9Sstevel@tonic-gate 	if (unlock_fp == TRUE)
2830d216dff5SRobert Mastors 		rw_exit(&lsp->rls_state->rs_finfo->rf_file_rwlock);
2831d216dff5SRobert Mastors 	rfs4_dbe_rele(lsp->rls_dbe);
28327c478bd9Sstevel@tonic-gate }
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate static rfs4_lo_state_t *
rfs4_findlo_state(stateid_t * id,bool_t lock_fp)28357c478bd9Sstevel@tonic-gate rfs4_findlo_state(stateid_t *id, bool_t lock_fp)
28367c478bd9Sstevel@tonic-gate {
28377c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp;
28387c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
28390dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
28407c478bd9Sstevel@tonic-gate 
28410dfe541eSEvan Layton 	lsp = (rfs4_lo_state_t *)rfs4_dbsearch(nsrv4->rfs4_lo_state_idx, id,
2842ed57cab9Srg 	    &create, NULL, RFS4_DBS_VALID);
28437c478bd9Sstevel@tonic-gate 	if (lock_fp == TRUE && lsp != NULL)
2844d216dff5SRobert Mastors 		rw_enter(&lsp->rls_state->rs_finfo->rf_file_rwlock, RW_READER);
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 	return (lsp);
28477c478bd9Sstevel@tonic-gate }
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate 
28507c478bd9Sstevel@tonic-gate static uint32_t
lo_state_lo_hash(void * key)28517c478bd9Sstevel@tonic-gate lo_state_lo_hash(void *key)
28527c478bd9Sstevel@tonic-gate {
2853d216dff5SRobert Mastors 	rfs4_lo_state_t *lsp = key;
28547c478bd9Sstevel@tonic-gate 
2855d216dff5SRobert Mastors 	return (ADDRHASH(lsp->rls_locker) ^ ADDRHASH(lsp->rls_state));
28567c478bd9Sstevel@tonic-gate }
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate static bool_t
lo_state_lo_compare(rfs4_entry_t u_entry,void * key)28597c478bd9Sstevel@tonic-gate lo_state_lo_compare(rfs4_entry_t u_entry, void *key)
28607c478bd9Sstevel@tonic-gate {
2861d216dff5SRobert Mastors 	rfs4_lo_state_t *lsp = (rfs4_lo_state_t *)u_entry;
28627c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *keyp = key;
28637c478bd9Sstevel@tonic-gate 
2864d216dff5SRobert Mastors 	return (keyp->rls_locker == lsp->rls_locker &&
2865d216dff5SRobert Mastors 	    keyp->rls_state == lsp->rls_state);
28667c478bd9Sstevel@tonic-gate }
28677c478bd9Sstevel@tonic-gate 
28687c478bd9Sstevel@tonic-gate static void *
lo_state_lo_mkkey(rfs4_entry_t u_entry)28697c478bd9Sstevel@tonic-gate lo_state_lo_mkkey(rfs4_entry_t u_entry)
28707c478bd9Sstevel@tonic-gate {
28717c478bd9Sstevel@tonic-gate 	return (u_entry);
28727c478bd9Sstevel@tonic-gate }
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate rfs4_lo_state_t *
rfs4_findlo_state_by_owner(rfs4_lockowner_t * lo,rfs4_state_t * sp,bool_t * create)2875d216dff5SRobert Mastors rfs4_findlo_state_by_owner(rfs4_lockowner_t *lo, rfs4_state_t *sp,
2876d216dff5SRobert Mastors     bool_t *create)
28777c478bd9Sstevel@tonic-gate {
28787c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp;
28797c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t arg;
28800dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
28817c478bd9Sstevel@tonic-gate 
2882d216dff5SRobert Mastors 	arg.rls_locker = lo;
2883d216dff5SRobert Mastors 	arg.rls_state = sp;
28847c478bd9Sstevel@tonic-gate 
28850dfe541eSEvan Layton 	lsp = (rfs4_lo_state_t *)rfs4_dbsearch(nsrv4->rfs4_lo_state_owner_idx,
28860dfe541eSEvan Layton 	    &arg, create, &arg, RFS4_DBS_VALID);
28877c478bd9Sstevel@tonic-gate 
28887c478bd9Sstevel@tonic-gate 	return (lsp);
28897c478bd9Sstevel@tonic-gate }
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate static stateid_t
get_stateid(id_t eid)28927c478bd9Sstevel@tonic-gate get_stateid(id_t eid)
28937c478bd9Sstevel@tonic-gate {
28947c478bd9Sstevel@tonic-gate 	stateid_t id;
28950dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
28960dfe541eSEvan Layton 
28970dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
28987c478bd9Sstevel@tonic-gate 
28990dfe541eSEvan Layton 	id.bits.boottime = nsrv4->rfs4_start_time;
29007c478bd9Sstevel@tonic-gate 	id.bits.ident = eid;
29017c478bd9Sstevel@tonic-gate 	id.bits.chgseq = 0;
29027c478bd9Sstevel@tonic-gate 	id.bits.type = 0;
29037c478bd9Sstevel@tonic-gate 	id.bits.pid = 0;
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	/*
29067c478bd9Sstevel@tonic-gate 	 * If we are booted as a cluster node, embed our nodeid.
29077c478bd9Sstevel@tonic-gate 	 * We've already done sanity checks in rfs4_client_create() so no
29087c478bd9Sstevel@tonic-gate 	 * need to repeat them here.
29097c478bd9Sstevel@tonic-gate 	 */
29107c478bd9Sstevel@tonic-gate 	id.bits.clnodeid = (cluster_bootflags & CLUSTER_BOOTED) ?
29117c478bd9Sstevel@tonic-gate 	    clconf_get_nodeid() : 0;
29127c478bd9Sstevel@tonic-gate 
29137c478bd9Sstevel@tonic-gate 	return (id);
29147c478bd9Sstevel@tonic-gate }
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate /*
29177c478bd9Sstevel@tonic-gate  * For use only when booted as a cluster node.
29187c478bd9Sstevel@tonic-gate  * Returns TRUE if the embedded nodeid indicates that this stateid was
29197c478bd9Sstevel@tonic-gate  * generated on another node.
29207c478bd9Sstevel@tonic-gate  */
29217c478bd9Sstevel@tonic-gate static int
foreign_stateid(stateid_t * id)29227c478bd9Sstevel@tonic-gate foreign_stateid(stateid_t *id)
29237c478bd9Sstevel@tonic-gate {
29247c478bd9Sstevel@tonic-gate 	ASSERT(cluster_bootflags & CLUSTER_BOOTED);
29257c478bd9Sstevel@tonic-gate 	return (id->bits.clnodeid != (uint32_t)clconf_get_nodeid());
29267c478bd9Sstevel@tonic-gate }
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate /*
29297c478bd9Sstevel@tonic-gate  * For use only when booted as a cluster node.
29307c478bd9Sstevel@tonic-gate  * Returns TRUE if the embedded nodeid indicates that this clientid was
29317c478bd9Sstevel@tonic-gate  * generated on another node.
29327c478bd9Sstevel@tonic-gate  */
29337c478bd9Sstevel@tonic-gate static int
foreign_clientid(cid * cidp)29347c478bd9Sstevel@tonic-gate foreign_clientid(cid *cidp)
29357c478bd9Sstevel@tonic-gate {
29367c478bd9Sstevel@tonic-gate 	ASSERT(cluster_bootflags & CLUSTER_BOOTED);
29377c478bd9Sstevel@tonic-gate 	return (cidp->impl_id.c_id >> CLUSTER_NODEID_SHIFT !=
29387c478bd9Sstevel@tonic-gate 	    (uint32_t)clconf_get_nodeid());
29397c478bd9Sstevel@tonic-gate }
29407c478bd9Sstevel@tonic-gate 
29417c478bd9Sstevel@tonic-gate /*
29427c478bd9Sstevel@tonic-gate  * For use only when booted as a cluster node.
29437c478bd9Sstevel@tonic-gate  * Embed our cluster nodeid into the clientid.
29447c478bd9Sstevel@tonic-gate  */
29457c478bd9Sstevel@tonic-gate static void
embed_nodeid(cid * cidp)29467c478bd9Sstevel@tonic-gate embed_nodeid(cid *cidp)
29477c478bd9Sstevel@tonic-gate {
29487c478bd9Sstevel@tonic-gate 	int clnodeid;
29497c478bd9Sstevel@tonic-gate 	/*
29507c478bd9Sstevel@tonic-gate 	 * Currently, our state tables are small enough that their
29517c478bd9Sstevel@tonic-gate 	 * ids will leave enough bits free for the nodeid. If the
29527c478bd9Sstevel@tonic-gate 	 * tables become larger, we mustn't overwrite the id.
29537c478bd9Sstevel@tonic-gate 	 * Equally, we only have room for so many bits of nodeid, so
29547c478bd9Sstevel@tonic-gate 	 * must check that too.
29557c478bd9Sstevel@tonic-gate 	 */
29567c478bd9Sstevel@tonic-gate 	ASSERT(cluster_bootflags & CLUSTER_BOOTED);
29577c478bd9Sstevel@tonic-gate 	ASSERT(cidp->impl_id.c_id >> CLUSTER_NODEID_SHIFT == 0);
29587c478bd9Sstevel@tonic-gate 	clnodeid = clconf_get_nodeid();
29597c478bd9Sstevel@tonic-gate 	ASSERT(clnodeid <= CLUSTER_MAX_NODEID);
29607c478bd9Sstevel@tonic-gate 	ASSERT(clnodeid != NODEID_UNKNOWN);
29617c478bd9Sstevel@tonic-gate 	cidp->impl_id.c_id |= (clnodeid << CLUSTER_NODEID_SHIFT);
29627c478bd9Sstevel@tonic-gate }
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate static uint32_t
state_hash(void * key)29657c478bd9Sstevel@tonic-gate state_hash(void *key)
29667c478bd9Sstevel@tonic-gate {
29677c478bd9Sstevel@tonic-gate 	stateid_t *ip = (stateid_t *)key;
29687c478bd9Sstevel@tonic-gate 
29697c478bd9Sstevel@tonic-gate 	return (ip->bits.ident);
29707c478bd9Sstevel@tonic-gate }
29717c478bd9Sstevel@tonic-gate 
29727c478bd9Sstevel@tonic-gate static bool_t
state_compare(rfs4_entry_t u_entry,void * key)29737c478bd9Sstevel@tonic-gate state_compare(rfs4_entry_t u_entry, void *key)
29747c478bd9Sstevel@tonic-gate {
29757c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
29767c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)key;
29777c478bd9Sstevel@tonic-gate 	bool_t rc;
29787c478bd9Sstevel@tonic-gate 
2979d216dff5SRobert Mastors 	rc = (sp->rs_stateid.bits.boottime == id->bits.boottime &&
2980d216dff5SRobert Mastors 	    sp->rs_stateid.bits.ident == id->bits.ident);
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	return (rc);
29837c478bd9Sstevel@tonic-gate }
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate static void *
state_mkkey(rfs4_entry_t u_entry)29867c478bd9Sstevel@tonic-gate state_mkkey(rfs4_entry_t u_entry)
29877c478bd9Sstevel@tonic-gate {
29887c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
29897c478bd9Sstevel@tonic-gate 
2990d216dff5SRobert Mastors 	return (&sp->rs_stateid);
29917c478bd9Sstevel@tonic-gate }
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate static void
rfs4_state_destroy(rfs4_entry_t u_entry)29947c478bd9Sstevel@tonic-gate rfs4_state_destroy(rfs4_entry_t u_entry)
29957c478bd9Sstevel@tonic-gate {
29967c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
29977c478bd9Sstevel@tonic-gate 
2998d216dff5SRobert Mastors 	/* remove from openowner list */
2999d216dff5SRobert Mastors 	rfs4_dbe_lock(sp->rs_owner->ro_dbe);
3000d216dff5SRobert Mastors 	list_remove(&sp->rs_owner->ro_statelist, sp);
3001d216dff5SRobert Mastors 	rfs4_dbe_unlock(sp->rs_owner->ro_dbe);
3002d216dff5SRobert Mastors 
3003d216dff5SRobert Mastors 	list_destroy(&sp->rs_lostatelist);
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 	/* release any share locks for this stateid if it's still open */
3006d216dff5SRobert Mastors 	if (!sp->rs_closed) {
3007d216dff5SRobert Mastors 		rfs4_dbe_lock(sp->rs_dbe);
3008d216dff5SRobert Mastors 		(void) rfs4_unshare(sp);
3009d216dff5SRobert Mastors 		rfs4_dbe_unlock(sp->rs_dbe);
3010d216dff5SRobert Mastors 	}
30117c478bd9Sstevel@tonic-gate 
30127c478bd9Sstevel@tonic-gate 	/* Were done with the file */
3013d216dff5SRobert Mastors 	rfs4_file_rele(sp->rs_finfo);
3014d216dff5SRobert Mastors 	sp->rs_finfo = NULL;
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate 	/* And now with the openowner */
3017d216dff5SRobert Mastors 	rfs4_openowner_rele(sp->rs_owner);
3018d216dff5SRobert Mastors 	sp->rs_owner = NULL;
30197c478bd9Sstevel@tonic-gate }
30207c478bd9Sstevel@tonic-gate 
30217c478bd9Sstevel@tonic-gate static void
rfs4_state_rele_nounlock(rfs4_state_t * sp)30227c478bd9Sstevel@tonic-gate rfs4_state_rele_nounlock(rfs4_state_t *sp)
30237c478bd9Sstevel@tonic-gate {
3024d216dff5SRobert Mastors 	rfs4_dbe_rele(sp->rs_dbe);
30257c478bd9Sstevel@tonic-gate }
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate void
rfs4_state_rele(rfs4_state_t * sp)30287c478bd9Sstevel@tonic-gate rfs4_state_rele(rfs4_state_t *sp)
30297c478bd9Sstevel@tonic-gate {
3030d216dff5SRobert Mastors 	rw_exit(&sp->rs_finfo->rf_file_rwlock);
3031d216dff5SRobert Mastors 	rfs4_dbe_rele(sp->rs_dbe);
30327c478bd9Sstevel@tonic-gate }
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate static uint32_t
deleg_hash(void * key)30357c478bd9Sstevel@tonic-gate deleg_hash(void *key)
30367c478bd9Sstevel@tonic-gate {
30377c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)key;
30387c478bd9Sstevel@tonic-gate 
3039d216dff5SRobert Mastors 	return (ADDRHASH(dsp->rds_client) ^ ADDRHASH(dsp->rds_finfo));
30407c478bd9Sstevel@tonic-gate }
30417c478bd9Sstevel@tonic-gate 
30427c478bd9Sstevel@tonic-gate static bool_t
deleg_compare(rfs4_entry_t u_entry,void * key)30437c478bd9Sstevel@tonic-gate deleg_compare(rfs4_entry_t u_entry, void *key)
30447c478bd9Sstevel@tonic-gate {
30457c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)u_entry;
30467c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *kdsp = (rfs4_deleg_state_t *)key;
30477c478bd9Sstevel@tonic-gate 
3048d216dff5SRobert Mastors 	return (dsp->rds_client == kdsp->rds_client &&
3049d216dff5SRobert Mastors 	    dsp->rds_finfo == kdsp->rds_finfo);
30507c478bd9Sstevel@tonic-gate }
30517c478bd9Sstevel@tonic-gate 
30527c478bd9Sstevel@tonic-gate static void *
deleg_mkkey(rfs4_entry_t u_entry)30537c478bd9Sstevel@tonic-gate deleg_mkkey(rfs4_entry_t u_entry)
30547c478bd9Sstevel@tonic-gate {
30557c478bd9Sstevel@tonic-gate 	return (u_entry);
30567c478bd9Sstevel@tonic-gate }
30577c478bd9Sstevel@tonic-gate 
30587c478bd9Sstevel@tonic-gate static uint32_t
deleg_state_hash(void * key)30597c478bd9Sstevel@tonic-gate deleg_state_hash(void *key)
30607c478bd9Sstevel@tonic-gate {
30617c478bd9Sstevel@tonic-gate 	stateid_t *ip = (stateid_t *)key;
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 	return (ip->bits.ident);
30647c478bd9Sstevel@tonic-gate }
30657c478bd9Sstevel@tonic-gate 
30667c478bd9Sstevel@tonic-gate static bool_t
deleg_state_compare(rfs4_entry_t u_entry,void * key)30677c478bd9Sstevel@tonic-gate deleg_state_compare(rfs4_entry_t u_entry, void *key)
30687c478bd9Sstevel@tonic-gate {
30697c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)u_entry;
30707c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)key;
30717c478bd9Sstevel@tonic-gate 	bool_t rc;
30727c478bd9Sstevel@tonic-gate 
30737c478bd9Sstevel@tonic-gate 	if (id->bits.type != DELEGID)
30747c478bd9Sstevel@tonic-gate 		return (FALSE);
30757c478bd9Sstevel@tonic-gate 
3076d216dff5SRobert Mastors 	rc = (dsp->rds_delegid.bits.boottime == id->bits.boottime &&
3077d216dff5SRobert Mastors 	    dsp->rds_delegid.bits.ident == id->bits.ident);
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 	return (rc);
30807c478bd9Sstevel@tonic-gate }
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate static void *
deleg_state_mkkey(rfs4_entry_t u_entry)30837c478bd9Sstevel@tonic-gate deleg_state_mkkey(rfs4_entry_t u_entry)
30847c478bd9Sstevel@tonic-gate {
30857c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)u_entry;
30867c478bd9Sstevel@tonic-gate 
3087d216dff5SRobert Mastors 	return (&dsp->rds_delegid);
30887c478bd9Sstevel@tonic-gate }
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate static bool_t
rfs4_deleg_state_expiry(rfs4_entry_t u_entry)30917c478bd9Sstevel@tonic-gate rfs4_deleg_state_expiry(rfs4_entry_t u_entry)
30927c478bd9Sstevel@tonic-gate {
30937c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)u_entry;
30947c478bd9Sstevel@tonic-gate 
3095d216dff5SRobert Mastors 	if (rfs4_dbe_is_invalid(dsp->rds_dbe))
30967c478bd9Sstevel@tonic-gate 		return (TRUE);
30977c478bd9Sstevel@tonic-gate 
3098eec118a1SMarcel Telka 	if (dsp->rds_dtype == OPEN_DELEGATE_NONE)
3099eec118a1SMarcel Telka 		return (TRUE);
3100eec118a1SMarcel Telka 
3101d216dff5SRobert Mastors 	if ((gethrestime_sec() - dsp->rds_client->rc_last_access
3102ed57cab9Srg 	    > rfs4_lease_time)) {
3103d216dff5SRobert Mastors 		rfs4_dbe_invalidate(dsp->rds_dbe);
3104ed57cab9Srg 		return (TRUE);
3105ed57cab9Srg 	}
3106ed57cab9Srg 
3107ed57cab9Srg 	return (FALSE);
31087c478bd9Sstevel@tonic-gate }
31097c478bd9Sstevel@tonic-gate 
31107c478bd9Sstevel@tonic-gate static bool_t
rfs4_deleg_state_create(rfs4_entry_t u_entry,void * argp)31117c478bd9Sstevel@tonic-gate rfs4_deleg_state_create(rfs4_entry_t u_entry, void *argp)
31127c478bd9Sstevel@tonic-gate {
31137c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)u_entry;
3114d216dff5SRobert Mastors 	rfs4_file_t *fp = ((rfs4_deleg_state_t *)argp)->rds_finfo;
3115d216dff5SRobert Mastors 	rfs4_client_t *cp = ((rfs4_deleg_state_t *)argp)->rds_client;
31167c478bd9Sstevel@tonic-gate 
3117d216dff5SRobert Mastors 	rfs4_dbe_hold(fp->rf_dbe);
3118d216dff5SRobert Mastors 	rfs4_dbe_hold(cp->rc_dbe);
31197c478bd9Sstevel@tonic-gate 
3120d216dff5SRobert Mastors 	dsp->rds_delegid = get_stateid(rfs4_dbe_getid(dsp->rds_dbe));
3121d216dff5SRobert Mastors 	dsp->rds_delegid.bits.type = DELEGID;
3122d216dff5SRobert Mastors 	dsp->rds_finfo = fp;
3123d216dff5SRobert Mastors 	dsp->rds_client = cp;
3124d216dff5SRobert Mastors 	dsp->rds_dtype = OPEN_DELEGATE_NONE;
31257c478bd9Sstevel@tonic-gate 
3126d216dff5SRobert Mastors 	dsp->rds_time_granted = gethrestime_sec();	/* observability */
3127d216dff5SRobert Mastors 	dsp->rds_time_revoked = 0;
31287c478bd9Sstevel@tonic-gate 
3129d216dff5SRobert Mastors 	list_link_init(&dsp->rds_node);
31307c478bd9Sstevel@tonic-gate 
31317c478bd9Sstevel@tonic-gate 	return (TRUE);
31327c478bd9Sstevel@tonic-gate }
31337c478bd9Sstevel@tonic-gate 
31347c478bd9Sstevel@tonic-gate static void
rfs4_deleg_state_destroy(rfs4_entry_t u_entry)31357c478bd9Sstevel@tonic-gate rfs4_deleg_state_destroy(rfs4_entry_t u_entry)
31367c478bd9Sstevel@tonic-gate {
31377c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)u_entry;
31387c478bd9Sstevel@tonic-gate 
3139d216dff5SRobert Mastors 	/* return delegation if necessary */
3140d216dff5SRobert Mastors 	rfs4_return_deleg(dsp, FALSE);
31417c478bd9Sstevel@tonic-gate 
31427c478bd9Sstevel@tonic-gate 	/* Were done with the file */
3143d216dff5SRobert Mastors 	rfs4_file_rele(dsp->rds_finfo);
3144d216dff5SRobert Mastors 	dsp->rds_finfo = NULL;
31457c478bd9Sstevel@tonic-gate 
31467c478bd9Sstevel@tonic-gate 	/* And now with the openowner */
3147d216dff5SRobert Mastors 	rfs4_client_rele(dsp->rds_client);
3148d216dff5SRobert Mastors 	dsp->rds_client = NULL;
31497c478bd9Sstevel@tonic-gate }
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate rfs4_deleg_state_t *
rfs4_finddeleg(rfs4_state_t * sp,bool_t * create)31527c478bd9Sstevel@tonic-gate rfs4_finddeleg(rfs4_state_t *sp, bool_t *create)
31537c478bd9Sstevel@tonic-gate {
31547c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t ds, *dsp;
31550dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
31567c478bd9Sstevel@tonic-gate 
3157d216dff5SRobert Mastors 	ds.rds_client = sp->rs_owner->ro_client;
3158d216dff5SRobert Mastors 	ds.rds_finfo = sp->rs_finfo;
31597c478bd9Sstevel@tonic-gate 
31600dfe541eSEvan Layton 	dsp = (rfs4_deleg_state_t *)rfs4_dbsearch(nsrv4->rfs4_deleg_idx, &ds,
3161ed57cab9Srg 	    create, &ds, RFS4_DBS_VALID);
31627c478bd9Sstevel@tonic-gate 
31637c478bd9Sstevel@tonic-gate 	return (dsp);
31647c478bd9Sstevel@tonic-gate }
31657c478bd9Sstevel@tonic-gate 
31667c478bd9Sstevel@tonic-gate rfs4_deleg_state_t *
rfs4_finddelegstate(stateid_t * id)31677c478bd9Sstevel@tonic-gate rfs4_finddelegstate(stateid_t *id)
31687c478bd9Sstevel@tonic-gate {
31697c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp;
31707c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
31710dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
31727c478bd9Sstevel@tonic-gate 
31730dfe541eSEvan Layton 	dsp = (rfs4_deleg_state_t *)rfs4_dbsearch(nsrv4->rfs4_deleg_state_idx,
31740dfe541eSEvan Layton 	    id, &create, NULL, RFS4_DBS_VALID);
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate 	return (dsp);
31777c478bd9Sstevel@tonic-gate }
31787c478bd9Sstevel@tonic-gate 
31797c478bd9Sstevel@tonic-gate void
rfs4_deleg_state_rele(rfs4_deleg_state_t * dsp)31807c478bd9Sstevel@tonic-gate rfs4_deleg_state_rele(rfs4_deleg_state_t *dsp)
31817c478bd9Sstevel@tonic-gate {
3182d216dff5SRobert Mastors 	rfs4_dbe_rele(dsp->rds_dbe);
31837c478bd9Sstevel@tonic-gate }
31847c478bd9Sstevel@tonic-gate 
31857c478bd9Sstevel@tonic-gate void
rfs4_update_lock_sequence(rfs4_lo_state_t * lsp)31867c478bd9Sstevel@tonic-gate rfs4_update_lock_sequence(rfs4_lo_state_t *lsp)
31877c478bd9Sstevel@tonic-gate {
31887c478bd9Sstevel@tonic-gate 
3189d216dff5SRobert Mastors 	rfs4_dbe_lock(lsp->rls_dbe);
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 	/*
31927c478bd9Sstevel@tonic-gate 	 * If we are skipping sequence id checking, this means that
31937c478bd9Sstevel@tonic-gate 	 * this is the first lock request and therefore the sequence
31947c478bd9Sstevel@tonic-gate 	 * id does not need to be updated.  This only happens on the
31957c478bd9Sstevel@tonic-gate 	 * first lock request for a lockowner
31967c478bd9Sstevel@tonic-gate 	 */
3197d216dff5SRobert Mastors 	if (!lsp->rls_skip_seqid_check)
3198d216dff5SRobert Mastors 		lsp->rls_seqid++;
31997c478bd9Sstevel@tonic-gate 
3200d216dff5SRobert Mastors 	rfs4_dbe_unlock(lsp->rls_dbe);
32017c478bd9Sstevel@tonic-gate }
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate void
rfs4_update_lock_resp(rfs4_lo_state_t * lsp,nfs_resop4 * resp)32047c478bd9Sstevel@tonic-gate rfs4_update_lock_resp(rfs4_lo_state_t *lsp, nfs_resop4 *resp)
32057c478bd9Sstevel@tonic-gate {
32067c478bd9Sstevel@tonic-gate 
3207d216dff5SRobert Mastors 	rfs4_dbe_lock(lsp->rls_dbe);
32087c478bd9Sstevel@tonic-gate 
3209d216dff5SRobert Mastors 	rfs4_free_reply(&lsp->rls_reply);
32107c478bd9Sstevel@tonic-gate 
3211d216dff5SRobert Mastors 	rfs4_copy_reply(&lsp->rls_reply, resp);
32127c478bd9Sstevel@tonic-gate 
3213d216dff5SRobert Mastors 	rfs4_dbe_unlock(lsp->rls_dbe);
32147c478bd9Sstevel@tonic-gate }
32157c478bd9Sstevel@tonic-gate 
32167c478bd9Sstevel@tonic-gate void
rfs4_free_opens(rfs4_openowner_t * oo,bool_t invalidate,bool_t close_of_client)3217d216dff5SRobert Mastors rfs4_free_opens(rfs4_openowner_t *oo, bool_t invalidate,
3218d216dff5SRobert Mastors     bool_t close_of_client)
32197c478bd9Sstevel@tonic-gate {
32207c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp;
32217c478bd9Sstevel@tonic-gate 
3222d216dff5SRobert Mastors 	rfs4_dbe_lock(oo->ro_dbe);
32237c478bd9Sstevel@tonic-gate 
3224d216dff5SRobert Mastors 	for (sp = list_head(&oo->ro_statelist); sp != NULL;
3225d216dff5SRobert Mastors 	    sp = list_next(&oo->ro_statelist, sp)) {
32267c478bd9Sstevel@tonic-gate 		rfs4_state_close(sp, FALSE, close_of_client, CRED());
32277c478bd9Sstevel@tonic-gate 		if (invalidate == TRUE)
3228d216dff5SRobert Mastors 			rfs4_dbe_invalidate(sp->rs_dbe);
32297c478bd9Sstevel@tonic-gate 	}
32307c478bd9Sstevel@tonic-gate 
3231d216dff5SRobert Mastors 	rfs4_dbe_invalidate(oo->ro_dbe);
3232d216dff5SRobert Mastors 	rfs4_dbe_unlock(oo->ro_dbe);
32337c478bd9Sstevel@tonic-gate }
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate static uint32_t
state_owner_file_hash(void * key)32367c478bd9Sstevel@tonic-gate state_owner_file_hash(void *key)
32377c478bd9Sstevel@tonic-gate {
32387c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = key;
32397c478bd9Sstevel@tonic-gate 
3240d216dff5SRobert Mastors 	return (ADDRHASH(sp->rs_owner) ^ ADDRHASH(sp->rs_finfo));
32417c478bd9Sstevel@tonic-gate }
32427c478bd9Sstevel@tonic-gate 
32437c478bd9Sstevel@tonic-gate static bool_t
state_owner_file_compare(rfs4_entry_t u_entry,void * key)32447c478bd9Sstevel@tonic-gate state_owner_file_compare(rfs4_entry_t u_entry, void *key)
32457c478bd9Sstevel@tonic-gate {
32467c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
32477c478bd9Sstevel@tonic-gate 	rfs4_state_t *arg = key;
32487c478bd9Sstevel@tonic-gate 
3249d216dff5SRobert Mastors 	if (sp->rs_closed == TRUE)
32507c478bd9Sstevel@tonic-gate 		return (FALSE);
32517c478bd9Sstevel@tonic-gate 
3252d216dff5SRobert Mastors 	return (arg->rs_owner == sp->rs_owner && arg->rs_finfo == sp->rs_finfo);
32537c478bd9Sstevel@tonic-gate }
32547c478bd9Sstevel@tonic-gate 
32557c478bd9Sstevel@tonic-gate static void *
state_owner_file_mkkey(rfs4_entry_t u_entry)32567c478bd9Sstevel@tonic-gate state_owner_file_mkkey(rfs4_entry_t u_entry)
32577c478bd9Sstevel@tonic-gate {
32587c478bd9Sstevel@tonic-gate 	return (u_entry);
32597c478bd9Sstevel@tonic-gate }
32607c478bd9Sstevel@tonic-gate 
32617c478bd9Sstevel@tonic-gate static uint32_t
state_file_hash(void * key)32627c478bd9Sstevel@tonic-gate state_file_hash(void *key)
32637c478bd9Sstevel@tonic-gate {
32647c478bd9Sstevel@tonic-gate 	return (ADDRHASH(key));
32657c478bd9Sstevel@tonic-gate }
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate static bool_t
state_file_compare(rfs4_entry_t u_entry,void * key)32687c478bd9Sstevel@tonic-gate state_file_compare(rfs4_entry_t u_entry, void *key)
32697c478bd9Sstevel@tonic-gate {
32707c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
32717c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp = key;
32727c478bd9Sstevel@tonic-gate 
3273d216dff5SRobert Mastors 	if (sp->rs_closed == TRUE)
32747c478bd9Sstevel@tonic-gate 		return (FALSE);
32757c478bd9Sstevel@tonic-gate 
3276d216dff5SRobert Mastors 	return (fp == sp->rs_finfo);
32777c478bd9Sstevel@tonic-gate }
32787c478bd9Sstevel@tonic-gate 
32797c478bd9Sstevel@tonic-gate static void *
state_file_mkkey(rfs4_entry_t u_entry)32807c478bd9Sstevel@tonic-gate state_file_mkkey(rfs4_entry_t u_entry)
32817c478bd9Sstevel@tonic-gate {
32827c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
32837c478bd9Sstevel@tonic-gate 
3284d216dff5SRobert Mastors 	return (sp->rs_finfo);
32857c478bd9Sstevel@tonic-gate }
32867c478bd9Sstevel@tonic-gate 
32877c478bd9Sstevel@tonic-gate rfs4_state_t *
rfs4_findstate_by_owner_file(rfs4_openowner_t * oo,rfs4_file_t * fp,bool_t * create)3288d216dff5SRobert Mastors rfs4_findstate_by_owner_file(rfs4_openowner_t *oo, rfs4_file_t *fp,
32890dfe541eSEvan Layton     bool_t *create)
32907c478bd9Sstevel@tonic-gate {
32917c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp;
32927c478bd9Sstevel@tonic-gate 	rfs4_state_t key;
32930dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
32947c478bd9Sstevel@tonic-gate 
3295d216dff5SRobert Mastors 	key.rs_owner = oo;
3296d216dff5SRobert Mastors 	key.rs_finfo = fp;
32977c478bd9Sstevel@tonic-gate 
32980dfe541eSEvan Layton 	sp = (rfs4_state_t *)rfs4_dbsearch(nsrv4->rfs4_state_owner_file_idx,
32990dfe541eSEvan Layton 	    &key, create, &key, RFS4_DBS_VALID);
33007c478bd9Sstevel@tonic-gate 
33017c478bd9Sstevel@tonic-gate 	return (sp);
33027c478bd9Sstevel@tonic-gate }
33037c478bd9Sstevel@tonic-gate 
33047c478bd9Sstevel@tonic-gate /* This returns ANY state struct that refers to this file */
33057c478bd9Sstevel@tonic-gate static rfs4_state_t *
rfs4_findstate_by_file(rfs4_file_t * fp)33067c478bd9Sstevel@tonic-gate rfs4_findstate_by_file(rfs4_file_t *fp)
33077c478bd9Sstevel@tonic-gate {
33087c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
33090dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
33107c478bd9Sstevel@tonic-gate 
33110dfe541eSEvan Layton 	return ((rfs4_state_t *)rfs4_dbsearch(nsrv4->rfs4_state_file_idx, fp,
3312ed57cab9Srg 	    &create, fp, RFS4_DBS_VALID));
33137c478bd9Sstevel@tonic-gate }
33147c478bd9Sstevel@tonic-gate 
33157c478bd9Sstevel@tonic-gate static bool_t
rfs4_state_expiry(rfs4_entry_t u_entry)33167c478bd9Sstevel@tonic-gate rfs4_state_expiry(rfs4_entry_t u_entry)
33177c478bd9Sstevel@tonic-gate {
33187c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
33197c478bd9Sstevel@tonic-gate 
3320d216dff5SRobert Mastors 	if (rfs4_dbe_is_invalid(sp->rs_dbe))
33217c478bd9Sstevel@tonic-gate 		return (TRUE);
33227c478bd9Sstevel@tonic-gate 
3323d216dff5SRobert Mastors 	if (sp->rs_closed == TRUE &&
3324d216dff5SRobert Mastors 	    ((gethrestime_sec() - rfs4_dbe_get_timerele(sp->rs_dbe))
3325ed57cab9Srg 	    > rfs4_lease_time))
33267c478bd9Sstevel@tonic-gate 		return (TRUE);
33277c478bd9Sstevel@tonic-gate 
3328d216dff5SRobert Mastors 	return ((gethrestime_sec() - sp->rs_owner->ro_client->rc_last_access
3329ed57cab9Srg 	    > rfs4_lease_time));
33307c478bd9Sstevel@tonic-gate }
33317c478bd9Sstevel@tonic-gate 
33327c478bd9Sstevel@tonic-gate static bool_t
rfs4_state_create(rfs4_entry_t u_entry,void * argp)33337c478bd9Sstevel@tonic-gate rfs4_state_create(rfs4_entry_t u_entry, void *argp)
33347c478bd9Sstevel@tonic-gate {
33357c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
3336d216dff5SRobert Mastors 	rfs4_file_t *fp = ((rfs4_state_t *)argp)->rs_finfo;
3337d216dff5SRobert Mastors 	rfs4_openowner_t *oo = ((rfs4_state_t *)argp)->rs_owner;
33387c478bd9Sstevel@tonic-gate 
3339d216dff5SRobert Mastors 	rfs4_dbe_hold(fp->rf_dbe);
3340d216dff5SRobert Mastors 	rfs4_dbe_hold(oo->ro_dbe);
3341d216dff5SRobert Mastors 	sp->rs_stateid = get_stateid(rfs4_dbe_getid(sp->rs_dbe));
3342d216dff5SRobert Mastors 	sp->rs_stateid.bits.type = OPENID;
3343d216dff5SRobert Mastors 	sp->rs_owner = oo;
3344d216dff5SRobert Mastors 	sp->rs_finfo = fp;
33457c478bd9Sstevel@tonic-gate 
3346d216dff5SRobert Mastors 	list_create(&sp->rs_lostatelist, sizeof (rfs4_lo_state_t),
3347d216dff5SRobert Mastors 	    offsetof(rfs4_lo_state_t, rls_node));
33487c478bd9Sstevel@tonic-gate 
3349d216dff5SRobert Mastors 	/* Insert state on per open owner's list */
3350d216dff5SRobert Mastors 	rfs4_dbe_lock(oo->ro_dbe);
3351d216dff5SRobert Mastors 	list_insert_tail(&oo->ro_statelist, sp);
3352d216dff5SRobert Mastors 	rfs4_dbe_unlock(oo->ro_dbe);
33537c478bd9Sstevel@tonic-gate 
33547c478bd9Sstevel@tonic-gate 	return (TRUE);
33557c478bd9Sstevel@tonic-gate }
33567c478bd9Sstevel@tonic-gate 
33577c478bd9Sstevel@tonic-gate static rfs4_state_t *
rfs4_findstate(stateid_t * id,rfs4_dbsearch_type_t find_invalid,bool_t lock_fp)3358d216dff5SRobert Mastors rfs4_findstate(stateid_t *id, rfs4_dbsearch_type_t find_invalid, bool_t lock_fp)
33597c478bd9Sstevel@tonic-gate {
33607c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp;
33617c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
33620dfe541eSEvan Layton 	nfs4_srv_t *nsrv4 = nfs4_get_srv();
33637c478bd9Sstevel@tonic-gate 
33640dfe541eSEvan Layton 	sp = (rfs4_state_t *)rfs4_dbsearch(nsrv4->rfs4_state_idx, id,
3365ed57cab9Srg 	    &create, NULL, find_invalid);
33667c478bd9Sstevel@tonic-gate 	if (lock_fp == TRUE && sp != NULL)
3367d216dff5SRobert Mastors 		rw_enter(&sp->rs_finfo->rf_file_rwlock, RW_READER);
33687c478bd9Sstevel@tonic-gate 
33697c478bd9Sstevel@tonic-gate 	return (sp);
33707c478bd9Sstevel@tonic-gate }
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate void
rfs4_state_close(rfs4_state_t * sp,bool_t lock_held,bool_t close_of_client,cred_t * cr)3373d216dff5SRobert Mastors rfs4_state_close(rfs4_state_t *sp, bool_t lock_held, bool_t close_of_client,
3374d216dff5SRobert Mastors     cred_t *cr)
33757c478bd9Sstevel@tonic-gate {
33767c478bd9Sstevel@tonic-gate 	/* Remove the associated lo_state owners */
33777c478bd9Sstevel@tonic-gate 	if (!lock_held)
3378d216dff5SRobert Mastors 		rfs4_dbe_lock(sp->rs_dbe);
33797c478bd9Sstevel@tonic-gate 
3380c420ca07Smaheshvs 	/*
3381c420ca07Smaheshvs 	 * If refcnt == 0, the dbe is about to be destroyed.
3382c420ca07Smaheshvs 	 * lock state will be released by the reaper thread.
3383c420ca07Smaheshvs 	 */
3384c420ca07Smaheshvs 
3385d216dff5SRobert Mastors 	if (rfs4_dbe_refcnt(sp->rs_dbe) > 0) {
3386d216dff5SRobert Mastors 		if (sp->rs_closed == FALSE) {
3387c420ca07Smaheshvs 			rfs4_release_share_lock_state(sp, cr, close_of_client);
3388d216dff5SRobert Mastors 			sp->rs_closed = TRUE;
3389c420ca07Smaheshvs 		}
33907c478bd9Sstevel@tonic-gate 	}
3391c420ca07Smaheshvs 
33927c478bd9Sstevel@tonic-gate 	if (!lock_held)
3393d216dff5SRobert Mastors 		rfs4_dbe_unlock(sp->rs_dbe);
33947c478bd9Sstevel@tonic-gate }
33957c478bd9Sstevel@tonic-gate 
33967c478bd9Sstevel@tonic-gate /*
33977c478bd9Sstevel@tonic-gate  * Remove all state associated with the given client.
33987c478bd9Sstevel@tonic-gate  */
33997c478bd9Sstevel@tonic-gate void
rfs4_client_state_remove(rfs4_client_t * cp)34007c478bd9Sstevel@tonic-gate rfs4_client_state_remove(rfs4_client_t *cp)
34017c478bd9Sstevel@tonic-gate {
3402d216dff5SRobert Mastors 	rfs4_openowner_t *oo;
34037c478bd9Sstevel@tonic-gate 
3404d216dff5SRobert Mastors 	rfs4_dbe_lock(cp->rc_dbe);
34057c478bd9Sstevel@tonic-gate 
3406d216dff5SRobert Mastors 	for (oo = list_head(&cp->rc_openownerlist); oo != NULL;
3407d216dff5SRobert Mastors 	    oo = list_next(&cp->rc_openownerlist, oo)) {
3408d216dff5SRobert Mastors 		rfs4_free_opens(oo, TRUE, TRUE);
34097c478bd9Sstevel@tonic-gate 	}
34107c478bd9Sstevel@tonic-gate 
3411d216dff5SRobert Mastors 	rfs4_dbe_unlock(cp->rc_dbe);
34127c478bd9Sstevel@tonic-gate }
34137c478bd9Sstevel@tonic-gate 
34147c478bd9Sstevel@tonic-gate void
rfs4_client_close(rfs4_client_t * cp)34157c478bd9Sstevel@tonic-gate rfs4_client_close(rfs4_client_t *cp)
34167c478bd9Sstevel@tonic-gate {
34177c478bd9Sstevel@tonic-gate 	/* Mark client as going away. */
3418d216dff5SRobert Mastors 	rfs4_dbe_lock(cp->rc_dbe);
3419d216dff5SRobert Mastors 	rfs4_dbe_invalidate(cp->rc_dbe);
3420d216dff5SRobert Mastors 	rfs4_dbe_unlock(cp->rc_dbe);
34217c478bd9Sstevel@tonic-gate 
34227c478bd9Sstevel@tonic-gate 	rfs4_client_state_remove(cp);
3423*f44e1126SVitaliy Gusev 	rfs4x_client_session_remove(cp);
34247c478bd9Sstevel@tonic-gate 
34257c478bd9Sstevel@tonic-gate 	/* Release the client */
34267c478bd9Sstevel@tonic-gate 	rfs4_client_rele(cp);
34277c478bd9Sstevel@tonic-gate }
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate nfsstat4
rfs4_check_clientid(clientid4 * cp,int setclid_confirm)34307c478bd9Sstevel@tonic-gate rfs4_check_clientid(clientid4 *cp, int setclid_confirm)
34317c478bd9Sstevel@tonic-gate {
34327c478bd9Sstevel@tonic-gate 	cid *cidp = (cid *) cp;
34330dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
34340dfe541eSEvan Layton 
34350dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate 	/*
34387c478bd9Sstevel@tonic-gate 	 * If we are booted as a cluster node, check the embedded nodeid.
34397c478bd9Sstevel@tonic-gate 	 * If it indicates that this clientid was generated on another node,
34407c478bd9Sstevel@tonic-gate 	 * inform the client accordingly.
34417c478bd9Sstevel@tonic-gate 	 */
34427c478bd9Sstevel@tonic-gate 	if (cluster_bootflags & CLUSTER_BOOTED && foreign_clientid(cidp))
34437c478bd9Sstevel@tonic-gate 		return (NFS4ERR_STALE_CLIENTID);
34447c478bd9Sstevel@tonic-gate 
34457c478bd9Sstevel@tonic-gate 	/*
34467c478bd9Sstevel@tonic-gate 	 * If the server start time matches the time provided
34477c478bd9Sstevel@tonic-gate 	 * by the client (via the clientid) and this is NOT a
34487c478bd9Sstevel@tonic-gate 	 * setclientid_confirm then return EXPIRED.
34497c478bd9Sstevel@tonic-gate 	 */
34500dfe541eSEvan Layton 	if (!setclid_confirm &&
34510dfe541eSEvan Layton 	    cidp->impl_id.start_time == nsrv4->rfs4_start_time)
34527c478bd9Sstevel@tonic-gate 		return (NFS4ERR_EXPIRED);
34537c478bd9Sstevel@tonic-gate 
34547c478bd9Sstevel@tonic-gate 	return (NFS4ERR_STALE_CLIENTID);
34557c478bd9Sstevel@tonic-gate }
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate /*
34587c478bd9Sstevel@tonic-gate  * This is used when a stateid has not been found amongst the
34597c478bd9Sstevel@tonic-gate  * current server's state.  Check the stateid to see if it
34607c478bd9Sstevel@tonic-gate  * was from this server instantiation or not.
34617c478bd9Sstevel@tonic-gate  */
34627c478bd9Sstevel@tonic-gate static nfsstat4
what_stateid_error(stateid_t * id,stateid_type_t type)34637c478bd9Sstevel@tonic-gate what_stateid_error(stateid_t *id, stateid_type_t type)
34647c478bd9Sstevel@tonic-gate {
34650dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
34660dfe541eSEvan Layton 
34670dfe541eSEvan Layton 	nsrv4 = nfs4_get_srv();
34680dfe541eSEvan Layton 
34697c478bd9Sstevel@tonic-gate 	/* If we are booted as a cluster node, was stateid locally generated? */
34707c478bd9Sstevel@tonic-gate 	if ((cluster_bootflags & CLUSTER_BOOTED) && foreign_stateid(id))
34717c478bd9Sstevel@tonic-gate 		return (NFS4ERR_STALE_STATEID);
34727c478bd9Sstevel@tonic-gate 
34737c478bd9Sstevel@tonic-gate 	/* If types don't match then no use checking further */
34747c478bd9Sstevel@tonic-gate 	if (type != id->bits.type)
34757c478bd9Sstevel@tonic-gate 		return (NFS4ERR_BAD_STATEID);
34767c478bd9Sstevel@tonic-gate 
347725a1318cSMarcel Telka 	/* From a different server instantiation, return STALE */
34780dfe541eSEvan Layton 	if (id->bits.boottime != nsrv4->rfs4_start_time)
34797c478bd9Sstevel@tonic-gate 		return (NFS4ERR_STALE_STATEID);
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate 	/*
34827c478bd9Sstevel@tonic-gate 	 * From this server but the state is most likely beyond lease
34837c478bd9Sstevel@tonic-gate 	 * timeout: return NFS4ERR_EXPIRED.  However, there is the
34847c478bd9Sstevel@tonic-gate 	 * case of a delegation stateid.  For delegations, there is a
34857c478bd9Sstevel@tonic-gate 	 * case where the state can be removed without the client's
34867c478bd9Sstevel@tonic-gate 	 * knowledge/consent: revocation.  In the case of delegation
34877c478bd9Sstevel@tonic-gate 	 * revocation, the delegation state will be removed and will
34887c478bd9Sstevel@tonic-gate 	 * not be found.  If the client does something like a
34897c478bd9Sstevel@tonic-gate 	 * DELEGRETURN or even a READ/WRITE with a delegatoin stateid
34907c478bd9Sstevel@tonic-gate 	 * that has been revoked, the server should return BAD_STATEID
34917c478bd9Sstevel@tonic-gate 	 * instead of the more common EXPIRED error.
34927c478bd9Sstevel@tonic-gate 	 */
34930dfe541eSEvan Layton 	if (id->bits.boottime == nsrv4->rfs4_start_time) {
34947c478bd9Sstevel@tonic-gate 		if (type == DELEGID)
34957c478bd9Sstevel@tonic-gate 			return (NFS4ERR_BAD_STATEID);
34967c478bd9Sstevel@tonic-gate 		else
34977c478bd9Sstevel@tonic-gate 			return (NFS4ERR_EXPIRED);
34987c478bd9Sstevel@tonic-gate 	}
34997c478bd9Sstevel@tonic-gate 
35007c478bd9Sstevel@tonic-gate 	return (NFS4ERR_BAD_STATEID);
35017c478bd9Sstevel@tonic-gate }
35027c478bd9Sstevel@tonic-gate 
35037c478bd9Sstevel@tonic-gate /*
35047c478bd9Sstevel@tonic-gate  * Used later on to find the various state structs.  When called from
35057c478bd9Sstevel@tonic-gate  * rfs4_check_stateid()->rfs4_get_all_state(), no file struct lock is
35067c478bd9Sstevel@tonic-gate  * taken (it is not needed) and helps on the read/write path with
35077c478bd9Sstevel@tonic-gate  * respect to performance.
35087c478bd9Sstevel@tonic-gate  */
35097c478bd9Sstevel@tonic-gate static nfsstat4
rfs4_get_state_lockit(stateid4 * stateid,rfs4_state_t ** spp,rfs4_dbsearch_type_t find_invalid,bool_t lock_fp)35107c478bd9Sstevel@tonic-gate rfs4_get_state_lockit(stateid4 *stateid, rfs4_state_t **spp,
3511d216dff5SRobert Mastors     rfs4_dbsearch_type_t find_invalid, bool_t lock_fp)
35127c478bd9Sstevel@tonic-gate {
35137c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)stateid;
35147c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp;
35157c478bd9Sstevel@tonic-gate 
35167c478bd9Sstevel@tonic-gate 	*spp = NULL;
35177c478bd9Sstevel@tonic-gate 
35187c478bd9Sstevel@tonic-gate 	/* If we are booted as a cluster node, was stateid locally generated? */
35197c478bd9Sstevel@tonic-gate 	if ((cluster_bootflags & CLUSTER_BOOTED) && foreign_stateid(id))
35207c478bd9Sstevel@tonic-gate 		return (NFS4ERR_STALE_STATEID);
35217c478bd9Sstevel@tonic-gate 
35227c478bd9Sstevel@tonic-gate 	sp = rfs4_findstate(id, find_invalid, lock_fp);
35237c478bd9Sstevel@tonic-gate 	if (sp == NULL) {
35247c478bd9Sstevel@tonic-gate 		return (what_stateid_error(id, OPENID));
35257c478bd9Sstevel@tonic-gate 	}
35267c478bd9Sstevel@tonic-gate 
3527d216dff5SRobert Mastors 	if (rfs4_lease_expired(sp->rs_owner->ro_client)) {
35287c478bd9Sstevel@tonic-gate 		if (lock_fp == TRUE)
35297c478bd9Sstevel@tonic-gate 			rfs4_state_rele(sp);
35307c478bd9Sstevel@tonic-gate 		else
35317c478bd9Sstevel@tonic-gate 			rfs4_state_rele_nounlock(sp);
35327c478bd9Sstevel@tonic-gate 		return (NFS4ERR_EXPIRED);
35337c478bd9Sstevel@tonic-gate 	}
35347c478bd9Sstevel@tonic-gate 
35357c478bd9Sstevel@tonic-gate 	*spp = sp;
35367c478bd9Sstevel@tonic-gate 
35377c478bd9Sstevel@tonic-gate 	return (NFS4_OK);
35387c478bd9Sstevel@tonic-gate }
35397c478bd9Sstevel@tonic-gate 
35407c478bd9Sstevel@tonic-gate nfsstat4
rfs4_get_state(stateid4 * stateid,rfs4_state_t ** spp,rfs4_dbsearch_type_t find_invalid)35417c478bd9Sstevel@tonic-gate rfs4_get_state(stateid4 *stateid, rfs4_state_t **spp,
3542d216dff5SRobert Mastors     rfs4_dbsearch_type_t find_invalid)
35437c478bd9Sstevel@tonic-gate {
35447c478bd9Sstevel@tonic-gate 	return (rfs4_get_state_lockit(stateid, spp, find_invalid, TRUE));
35457c478bd9Sstevel@tonic-gate }
35467c478bd9Sstevel@tonic-gate 
35477c478bd9Sstevel@tonic-gate int
rfs4_check_stateid_seqid(rfs4_state_t * sp,stateid4 * stateid,const compound_state_t * cs)3548*f44e1126SVitaliy Gusev rfs4_check_stateid_seqid(rfs4_state_t *sp, stateid4 *stateid,
3549*f44e1126SVitaliy Gusev     const compound_state_t *cs)
35507c478bd9Sstevel@tonic-gate {
35517c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)stateid;
3552*f44e1126SVitaliy Gusev 	bool_t has_session = rfs4_has_session(cs);
35537c478bd9Sstevel@tonic-gate 
3554d216dff5SRobert Mastors 	if (rfs4_lease_expired(sp->rs_owner->ro_client))
35557c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_EXPIRED);
35567c478bd9Sstevel@tonic-gate 
3557*f44e1126SVitaliy Gusev 	if (has_session && id->bits.chgseq == 0)
3558*f44e1126SVitaliy Gusev 		return (NFS4_CHECK_STATEID_OKAY);
3559*f44e1126SVitaliy Gusev 
35607c478bd9Sstevel@tonic-gate 	/* Stateid is some time in the future - that's bad */
3561d216dff5SRobert Mastors 	if (sp->rs_stateid.bits.chgseq < id->bits.chgseq)
35627c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_BAD);
35637c478bd9Sstevel@tonic-gate 
3564*f44e1126SVitaliy Gusev 	if (!has_session &&
3565*f44e1126SVitaliy Gusev 	    sp->rs_stateid.bits.chgseq == id->bits.chgseq + 1) {
35667c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_REPLAY);
3567*f44e1126SVitaliy Gusev 	}
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate 	/* Stateid is some time in the past - that's old */
3570d216dff5SRobert Mastors 	if (sp->rs_stateid.bits.chgseq > id->bits.chgseq)
35717c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_OLD);
35727c478bd9Sstevel@tonic-gate 
35737c478bd9Sstevel@tonic-gate 	/* Caller needs to know about confirmation before closure */
3574d216dff5SRobert Mastors 	if (sp->rs_owner->ro_need_confirm)
35757c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_UNCONFIRMED);
35767c478bd9Sstevel@tonic-gate 
3577d216dff5SRobert Mastors 	if (sp->rs_closed == TRUE)
35787c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_CLOSED);
35797c478bd9Sstevel@tonic-gate 
35807c478bd9Sstevel@tonic-gate 	return (NFS4_CHECK_STATEID_OKAY);
35817c478bd9Sstevel@tonic-gate }
35827c478bd9Sstevel@tonic-gate 
35837c478bd9Sstevel@tonic-gate int
rfs4_check_lo_stateid_seqid(rfs4_lo_state_t * lsp,stateid4 * stateid,const compound_state_t * cs)3584*f44e1126SVitaliy Gusev rfs4_check_lo_stateid_seqid(rfs4_lo_state_t *lsp, stateid4 *stateid,
3585*f44e1126SVitaliy Gusev     const compound_state_t *cs)
35867c478bd9Sstevel@tonic-gate {
35877c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)stateid;
3588*f44e1126SVitaliy Gusev 	bool_t has_session = rfs4_has_session(cs);
35897c478bd9Sstevel@tonic-gate 
3590d216dff5SRobert Mastors 	if (rfs4_lease_expired(lsp->rls_state->rs_owner->ro_client))
35917c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_EXPIRED);
35927c478bd9Sstevel@tonic-gate 
3593*f44e1126SVitaliy Gusev 	if (has_session && id->bits.chgseq == 0)
3594*f44e1126SVitaliy Gusev 		return (NFS4_CHECK_STATEID_OKAY);
3595*f44e1126SVitaliy Gusev 
35967c478bd9Sstevel@tonic-gate 	/* Stateid is some time in the future - that's bad */
3597d216dff5SRobert Mastors 	if (lsp->rls_lockid.bits.chgseq < id->bits.chgseq)
35987c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_BAD);
35997c478bd9Sstevel@tonic-gate 
3600*f44e1126SVitaliy Gusev 	if (!has_session &&
3601*f44e1126SVitaliy Gusev 	    lsp->rls_lockid.bits.chgseq == id->bits.chgseq + 1) {
36027c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_REPLAY);
3603*f44e1126SVitaliy Gusev 	}
36047c478bd9Sstevel@tonic-gate 
36057c478bd9Sstevel@tonic-gate 	/* Stateid is some time in the past - that's old */
3606d216dff5SRobert Mastors 	if (lsp->rls_lockid.bits.chgseq > id->bits.chgseq)
36077c478bd9Sstevel@tonic-gate 		return (NFS4_CHECK_STATEID_OLD);
36087c478bd9Sstevel@tonic-gate 
3609d216dff5SRobert Mastors 	if (lsp->rls_state->rs_closed == TRUE)
3610d216dff5SRobert Mastors 		return (NFS4_CHECK_STATEID_CLOSED);
3611d216dff5SRobert Mastors 
36127c478bd9Sstevel@tonic-gate 	return (NFS4_CHECK_STATEID_OKAY);
36137c478bd9Sstevel@tonic-gate }
36147c478bd9Sstevel@tonic-gate 
36157c478bd9Sstevel@tonic-gate nfsstat4
rfs4_get_deleg_state(stateid4 * stateid,rfs4_deleg_state_t ** dspp)36167c478bd9Sstevel@tonic-gate rfs4_get_deleg_state(stateid4 *stateid, rfs4_deleg_state_t **dspp)
36177c478bd9Sstevel@tonic-gate {
36187c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)stateid;
36197c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp;
36207c478bd9Sstevel@tonic-gate 
36217c478bd9Sstevel@tonic-gate 	*dspp = NULL;
36227c478bd9Sstevel@tonic-gate 
36237c478bd9Sstevel@tonic-gate 	/* If we are booted as a cluster node, was stateid locally generated? */
36247c478bd9Sstevel@tonic-gate 	if ((cluster_bootflags & CLUSTER_BOOTED) && foreign_stateid(id))
36257c478bd9Sstevel@tonic-gate 		return (NFS4ERR_STALE_STATEID);
36267c478bd9Sstevel@tonic-gate 
36277c478bd9Sstevel@tonic-gate 	dsp = rfs4_finddelegstate(id);
36287c478bd9Sstevel@tonic-gate 	if (dsp == NULL) {
36297c478bd9Sstevel@tonic-gate 		return (what_stateid_error(id, DELEGID));
36307c478bd9Sstevel@tonic-gate 	}
36317c478bd9Sstevel@tonic-gate 
3632d216dff5SRobert Mastors 	if (rfs4_lease_expired(dsp->rds_client)) {
36337c478bd9Sstevel@tonic-gate 		rfs4_deleg_state_rele(dsp);
36347c478bd9Sstevel@tonic-gate 		return (NFS4ERR_EXPIRED);
36357c478bd9Sstevel@tonic-gate 	}
36367c478bd9Sstevel@tonic-gate 
36377c478bd9Sstevel@tonic-gate 	*dspp = dsp;
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 	return (NFS4_OK);
36407c478bd9Sstevel@tonic-gate }
36417c478bd9Sstevel@tonic-gate 
36427c478bd9Sstevel@tonic-gate nfsstat4
rfs4_get_lo_state(stateid4 * stateid,rfs4_lo_state_t ** lspp,bool_t lock_fp)36437c478bd9Sstevel@tonic-gate rfs4_get_lo_state(stateid4 *stateid, rfs4_lo_state_t **lspp, bool_t lock_fp)
36447c478bd9Sstevel@tonic-gate {
36457c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)stateid;
36467c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp;
36477c478bd9Sstevel@tonic-gate 
36487c478bd9Sstevel@tonic-gate 	*lspp = NULL;
36497c478bd9Sstevel@tonic-gate 
36507c478bd9Sstevel@tonic-gate 	/* If we are booted as a cluster node, was stateid locally generated? */
36517c478bd9Sstevel@tonic-gate 	if ((cluster_bootflags & CLUSTER_BOOTED) && foreign_stateid(id))
36527c478bd9Sstevel@tonic-gate 		return (NFS4ERR_STALE_STATEID);
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate 	lsp = rfs4_findlo_state(id, lock_fp);
36557c478bd9Sstevel@tonic-gate 	if (lsp == NULL) {
36567c478bd9Sstevel@tonic-gate 		return (what_stateid_error(id, LOCKID));
36577c478bd9Sstevel@tonic-gate 	}
36587c478bd9Sstevel@tonic-gate 
3659d216dff5SRobert Mastors 	if (rfs4_lease_expired(lsp->rls_state->rs_owner->ro_client)) {
36607c478bd9Sstevel@tonic-gate 		rfs4_lo_state_rele(lsp, lock_fp);
36617c478bd9Sstevel@tonic-gate 		return (NFS4ERR_EXPIRED);
36627c478bd9Sstevel@tonic-gate 	}
36637c478bd9Sstevel@tonic-gate 
36647c478bd9Sstevel@tonic-gate 	*lspp = lsp;
36657c478bd9Sstevel@tonic-gate 
36667c478bd9Sstevel@tonic-gate 	return (NFS4_OK);
36677c478bd9Sstevel@tonic-gate }
36687c478bd9Sstevel@tonic-gate 
36697c478bd9Sstevel@tonic-gate static nfsstat4
rfs4_get_all_state(stateid4 * sid,rfs4_state_t ** spp,rfs4_deleg_state_t ** dspp,rfs4_lo_state_t ** lspp)36707c478bd9Sstevel@tonic-gate rfs4_get_all_state(stateid4 *sid, rfs4_state_t **spp,
3671d216dff5SRobert Mastors     rfs4_deleg_state_t **dspp, rfs4_lo_state_t **lspp)
36727c478bd9Sstevel@tonic-gate {
36737c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = NULL;
36747c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = NULL;
3675d216dff5SRobert Mastors 	rfs4_lo_state_t *lsp = NULL;
36767c478bd9Sstevel@tonic-gate 	stateid_t *id;
36777c478bd9Sstevel@tonic-gate 	nfsstat4 status;
36787c478bd9Sstevel@tonic-gate 
3679d216dff5SRobert Mastors 	*spp = NULL; *dspp = NULL; *lspp = NULL;
36807c478bd9Sstevel@tonic-gate 
36817c478bd9Sstevel@tonic-gate 	id = (stateid_t *)sid;
36827c478bd9Sstevel@tonic-gate 	switch (id->bits.type) {
36837c478bd9Sstevel@tonic-gate 	case OPENID:
36847c478bd9Sstevel@tonic-gate 		status = rfs4_get_state_lockit(sid, &sp, FALSE, FALSE);
36857c478bd9Sstevel@tonic-gate 		break;
36867c478bd9Sstevel@tonic-gate 	case DELEGID:
36877c478bd9Sstevel@tonic-gate 		status = rfs4_get_deleg_state(sid, &dsp);
36887c478bd9Sstevel@tonic-gate 		break;
36897c478bd9Sstevel@tonic-gate 	case LOCKID:
3690d216dff5SRobert Mastors 		status = rfs4_get_lo_state(sid, &lsp, FALSE);
36917c478bd9Sstevel@tonic-gate 		if (status == NFS4_OK) {
3692d216dff5SRobert Mastors 			sp = lsp->rls_state;
3693d216dff5SRobert Mastors 			rfs4_dbe_hold(sp->rs_dbe);
36947c478bd9Sstevel@tonic-gate 		}
36957c478bd9Sstevel@tonic-gate 		break;
36967c478bd9Sstevel@tonic-gate 	default:
36977c478bd9Sstevel@tonic-gate 		status = NFS4ERR_BAD_STATEID;
36987c478bd9Sstevel@tonic-gate 	}
36997c478bd9Sstevel@tonic-gate 
37007c478bd9Sstevel@tonic-gate 	if (status == NFS4_OK) {
37017c478bd9Sstevel@tonic-gate 		*spp = sp;
37027c478bd9Sstevel@tonic-gate 		*dspp = dsp;
3703d216dff5SRobert Mastors 		*lspp = lsp;
37047c478bd9Sstevel@tonic-gate 	}
37057c478bd9Sstevel@tonic-gate 
37067c478bd9Sstevel@tonic-gate 	return (status);
37077c478bd9Sstevel@tonic-gate }
37087c478bd9Sstevel@tonic-gate 
37097c478bd9Sstevel@tonic-gate /*
37107c478bd9Sstevel@tonic-gate  * Given the I/O mode (FREAD or FWRITE), this checks whether the
37117c478bd9Sstevel@tonic-gate  * rfs4_state_t struct has access to do this operation and if so
37127c478bd9Sstevel@tonic-gate  * return NFS4_OK; otherwise the proper NFSv4 error is returned.
37137c478bd9Sstevel@tonic-gate  */
37147c478bd9Sstevel@tonic-gate nfsstat4
rfs4_state_has_access(rfs4_state_t * sp,int mode,vnode_t * vp)37157c478bd9Sstevel@tonic-gate rfs4_state_has_access(rfs4_state_t *sp, int mode, vnode_t *vp)
37167c478bd9Sstevel@tonic-gate {
37177c478bd9Sstevel@tonic-gate 	nfsstat4 stat = NFS4_OK;
37187c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
37197c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
37207c478bd9Sstevel@tonic-gate 
3721d216dff5SRobert Mastors 	rfs4_dbe_lock(sp->rs_dbe);
37227c478bd9Sstevel@tonic-gate 	if (mode == FWRITE) {
3723d216dff5SRobert Mastors 		if (!(sp->rs_share_access & OPEN4_SHARE_ACCESS_WRITE)) {
37247c478bd9Sstevel@tonic-gate 			stat = NFS4ERR_OPENMODE;
37257c478bd9Sstevel@tonic-gate 		}
37267c478bd9Sstevel@tonic-gate 	} else if (mode == FREAD) {
3727d216dff5SRobert Mastors 		if (!(sp->rs_share_access & OPEN4_SHARE_ACCESS_READ)) {
37287c478bd9Sstevel@tonic-gate 			/*
37297c478bd9Sstevel@tonic-gate 			 * If we have OPENed the file with DENYing access
37307c478bd9Sstevel@tonic-gate 			 * to both READ and WRITE then no one else could
37317c478bd9Sstevel@tonic-gate 			 * have OPENed the file, hence no conflicting READ
37327c478bd9Sstevel@tonic-gate 			 * deny.  This check is merely an optimization.
37337c478bd9Sstevel@tonic-gate 			 */
3734d216dff5SRobert Mastors 			if (sp->rs_share_deny == OPEN4_SHARE_DENY_BOTH)
37357c478bd9Sstevel@tonic-gate 				goto out;
37367c478bd9Sstevel@tonic-gate 
37377c478bd9Sstevel@tonic-gate 			/* Check against file struct's DENY mode */
37387c478bd9Sstevel@tonic-gate 			fp = rfs4_findfile(vp, NULL, &create);
37397c478bd9Sstevel@tonic-gate 			if (fp != NULL) {
37407c478bd9Sstevel@tonic-gate 				int deny_read = 0;
3741d216dff5SRobert Mastors 				rfs4_dbe_lock(fp->rf_dbe);
37427c478bd9Sstevel@tonic-gate 				/*
37437c478bd9Sstevel@tonic-gate 				 * Check if any other open owner has the file
37447c478bd9Sstevel@tonic-gate 				 * OPENed with deny READ.
37457c478bd9Sstevel@tonic-gate 				 */
3746d216dff5SRobert Mastors 				if (sp->rs_share_deny & OPEN4_SHARE_DENY_READ)
37477c478bd9Sstevel@tonic-gate 					deny_read = 1;
3748eec118a1SMarcel Telka 				ASSERT(fp->rf_deny_read >= deny_read);
3749eec118a1SMarcel Telka 				if (fp->rf_deny_read > deny_read)
37507c478bd9Sstevel@tonic-gate 					stat = NFS4ERR_OPENMODE;
3751d216dff5SRobert Mastors 				rfs4_dbe_unlock(fp->rf_dbe);
37527c478bd9Sstevel@tonic-gate 				rfs4_file_rele(fp);
37537c478bd9Sstevel@tonic-gate 			}
37547c478bd9Sstevel@tonic-gate 		}
37557c478bd9Sstevel@tonic-gate 	} else {
37567c478bd9Sstevel@tonic-gate 		/* Illegal I/O mode */
37577c478bd9Sstevel@tonic-gate 		stat = NFS4ERR_INVAL;
37587c478bd9Sstevel@tonic-gate 	}
37597c478bd9Sstevel@tonic-gate out:
3760d216dff5SRobert Mastors 	rfs4_dbe_unlock(sp->rs_dbe);
37617c478bd9Sstevel@tonic-gate 	return (stat);
37627c478bd9Sstevel@tonic-gate }
37637c478bd9Sstevel@tonic-gate 
3764*f44e1126SVitaliy Gusev static nfsstat4
check_state_seqid(stateid_t * st,stateid_t * in,bool_t has_session)3765*f44e1126SVitaliy Gusev check_state_seqid(stateid_t *st, stateid_t *in, bool_t has_session)
3766*f44e1126SVitaliy Gusev {
3767*f44e1126SVitaliy Gusev 	/* rfc56661, section 8.2.2, "seqid to zero" */
3768*f44e1126SVitaliy Gusev 	if (has_session && in->bits.chgseq == 0)
3769*f44e1126SVitaliy Gusev 		return (NFS4_OK);
3770*f44e1126SVitaliy Gusev 
3771*f44e1126SVitaliy Gusev 	/* Seqid in the future? - that's bad */
3772*f44e1126SVitaliy Gusev 	if (st->bits.chgseq < in->bits.chgseq)
3773*f44e1126SVitaliy Gusev 		return (NFS4ERR_BAD_STATEID);
3774*f44e1126SVitaliy Gusev 
3775*f44e1126SVitaliy Gusev 	/* Seqid in the past? - that's old */
3776*f44e1126SVitaliy Gusev 	if (st->bits.chgseq > in->bits.chgseq)
3777*f44e1126SVitaliy Gusev 		return (NFS4ERR_OLD_STATEID);
3778*f44e1126SVitaliy Gusev 
3779*f44e1126SVitaliy Gusev 	return (NFS4_OK);
3780*f44e1126SVitaliy Gusev }
3781*f44e1126SVitaliy Gusev 
37827c478bd9Sstevel@tonic-gate /*
37837c478bd9Sstevel@tonic-gate  * Given the I/O mode (FREAD or FWRITE), the vnode, the stateid and whether
3784da6c28aaSamw  * the file is being truncated, return NFS4_OK if allowed or appropriate
37857c478bd9Sstevel@tonic-gate  * V4 error if not. Note NFS4ERR_DELAY will be returned and a recall on
37867c478bd9Sstevel@tonic-gate  * the associated file will be done if the I/O is not consistent with any
37877c478bd9Sstevel@tonic-gate  * delegation in effect on the file. Should be holding VOP_RWLOCK, either
3788da6c28aaSamw  * as reader or writer as appropriate. rfs4_op_open will acquire the
37897c478bd9Sstevel@tonic-gate  * VOP_RWLOCK as writer when setting up delegation. If the stateid is bad
37907c478bd9Sstevel@tonic-gate  * this routine will return NFS4ERR_BAD_STATEID. In addition, through the
37917c478bd9Sstevel@tonic-gate  * deleg parameter, we will return whether a write delegation is held by
37927c478bd9Sstevel@tonic-gate  * the client associated with this stateid.
37937c478bd9Sstevel@tonic-gate  * If the server instance associated with the relevant client is in its
37947c478bd9Sstevel@tonic-gate  * grace period, return NFS4ERR_GRACE.
37957c478bd9Sstevel@tonic-gate  */
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate nfsstat4
rfs4_check_stateid(int mode,vnode_t * vp,stateid4 * stateid,bool_t trunc,bool_t * deleg,bool_t do_access,caller_context_t * ct,compound_state_t * cs)37987c478bd9Sstevel@tonic-gate rfs4_check_stateid(int mode, vnode_t *vp,
3799d216dff5SRobert Mastors     stateid4 *stateid, bool_t trunc, bool_t *deleg,
3800*f44e1126SVitaliy Gusev     bool_t do_access, caller_context_t *ct, compound_state_t *cs)
38017c478bd9Sstevel@tonic-gate {
38027c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp;
38037c478bd9Sstevel@tonic-gate 	bool_t create = FALSE;
38047c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp;
38057c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp;
38067c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp;
38077c478bd9Sstevel@tonic-gate 	stateid_t *id = (stateid_t *)stateid;
38087c478bd9Sstevel@tonic-gate 	nfsstat4 stat = NFS4_OK;
3809*f44e1126SVitaliy Gusev 	bool_t use_ss = rfs4_has_session(cs);
38107c478bd9Sstevel@tonic-gate 
3811da6c28aaSamw 	if (ct != NULL) {
3812da6c28aaSamw 		ct->cc_sysid = 0;
3813da6c28aaSamw 		ct->cc_pid = 0;
3814da6c28aaSamw 		ct->cc_caller_id = nfs4_srv_caller_id;
381562b9fcbeSjwahlig 		ct->cc_flags = CC_DONTBLOCK;
3816da6c28aaSamw 	}
3817da6c28aaSamw 
38187c478bd9Sstevel@tonic-gate 	if (ISSPECIAL(stateid)) {
38197c478bd9Sstevel@tonic-gate 		fp = rfs4_findfile(vp, NULL, &create);
38207c478bd9Sstevel@tonic-gate 		if (fp == NULL)
38217c478bd9Sstevel@tonic-gate 			return (NFS4_OK);
3822*f44e1126SVitaliy Gusev 
3823d216dff5SRobert Mastors 		if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_NONE) {
38247c478bd9Sstevel@tonic-gate 			rfs4_file_rele(fp);
38257c478bd9Sstevel@tonic-gate 			return (NFS4_OK);
38267c478bd9Sstevel@tonic-gate 		}
38277c478bd9Sstevel@tonic-gate 		if (mode == FWRITE ||
3828d216dff5SRobert Mastors 		    fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_WRITE) {
38297c478bd9Sstevel@tonic-gate 			rfs4_recall_deleg(fp, trunc, NULL);
38307c478bd9Sstevel@tonic-gate 			rfs4_file_rele(fp);
38317c478bd9Sstevel@tonic-gate 			return (NFS4ERR_DELAY);
38327c478bd9Sstevel@tonic-gate 		}
38337c478bd9Sstevel@tonic-gate 		rfs4_file_rele(fp);
38347c478bd9Sstevel@tonic-gate 		return (NFS4_OK);
38357c478bd9Sstevel@tonic-gate 	} else {
38367c478bd9Sstevel@tonic-gate 		stat = rfs4_get_all_state(stateid, &sp, &dsp, &lsp);
38377c478bd9Sstevel@tonic-gate 		if (stat != NFS4_OK)
38387c478bd9Sstevel@tonic-gate 			return (stat);
3839*f44e1126SVitaliy Gusev 
38407c478bd9Sstevel@tonic-gate 		if (lsp != NULL) {
38417c478bd9Sstevel@tonic-gate 			/* Is associated server instance in its grace period? */
3842d216dff5SRobert Mastors 			if (rfs4_clnt_in_grace(lsp->rls_locker->rl_client)) {
38437c478bd9Sstevel@tonic-gate 				rfs4_lo_state_rele(lsp, FALSE);
38447c478bd9Sstevel@tonic-gate 				if (sp != NULL)
38457c478bd9Sstevel@tonic-gate 					rfs4_state_rele_nounlock(sp);
38467c478bd9Sstevel@tonic-gate 				return (NFS4ERR_GRACE);
38477c478bd9Sstevel@tonic-gate 			}
3848*f44e1126SVitaliy Gusev 
3849*f44e1126SVitaliy Gusev 			ASSERT(id->bits.type == LOCKID);
3850*f44e1126SVitaliy Gusev 			stat = check_state_seqid(&lsp->rls_lockid, id, use_ss);
3851*f44e1126SVitaliy Gusev 			if (stat) {
3852*f44e1126SVitaliy Gusev 				rfs4_lo_state_rele(lsp, FALSE);
3853*f44e1126SVitaliy Gusev 				if (sp)
3854*f44e1126SVitaliy Gusev 					rfs4_state_rele_nounlock(sp);
3855*f44e1126SVitaliy Gusev 				return (stat);
3856a57549b4SVitaliy Gusev 			}
3857*f44e1126SVitaliy Gusev 
3858*f44e1126SVitaliy Gusev 			/* Ensure specified filehandle matches */
3859*f44e1126SVitaliy Gusev 			if (lsp->rls_state->rs_finfo->rf_vp != vp) {
3860*f44e1126SVitaliy Gusev 				rfs4_lo_state_rele(lsp, FALSE);
3861*f44e1126SVitaliy Gusev 				if (sp != NULL)
3862*f44e1126SVitaliy Gusev 					rfs4_state_rele_nounlock(sp);
3863*f44e1126SVitaliy Gusev 				return (NFS4ERR_BAD_STATEID);
3864*f44e1126SVitaliy Gusev 			}
3865*f44e1126SVitaliy Gusev 
3866da6c28aaSamw 			if (ct != NULL) {
3867d216dff5SRobert Mastors 				ct->cc_sysid =
3868d216dff5SRobert Mastors 				    lsp->rls_locker->rl_client->rc_sysidt;
3869d216dff5SRobert Mastors 				ct->cc_pid = lsp->rls_locker->rl_pid;
3870da6c28aaSamw 			}
38717c478bd9Sstevel@tonic-gate 			rfs4_lo_state_rele(lsp, FALSE);
38727c478bd9Sstevel@tonic-gate 		}
38737c478bd9Sstevel@tonic-gate 
38747c478bd9Sstevel@tonic-gate 		/* Stateid provided was an "open" stateid */
38757c478bd9Sstevel@tonic-gate 		if (sp != NULL) {
38767c478bd9Sstevel@tonic-gate 			/* Is associated server instance in its grace period? */
3877d216dff5SRobert Mastors 			if (rfs4_clnt_in_grace(sp->rs_owner->ro_client)) {
38787c478bd9Sstevel@tonic-gate 				rfs4_state_rele_nounlock(sp);
38797c478bd9Sstevel@tonic-gate 				return (NFS4ERR_GRACE);
38807c478bd9Sstevel@tonic-gate 			}
3881*f44e1126SVitaliy Gusev 			/* Skip if is here via the LOCKID */
38827c478bd9Sstevel@tonic-gate 			if (id->bits.type == OPENID) {
3883*f44e1126SVitaliy Gusev 				stat = check_state_seqid(&sp->rs_stateid, id,
3884*f44e1126SVitaliy Gusev 				    use_ss);
3885*f44e1126SVitaliy Gusev 				if (stat) {
38867c478bd9Sstevel@tonic-gate 					rfs4_state_rele_nounlock(sp);
3887*f44e1126SVitaliy Gusev 					return (stat);
38887c478bd9Sstevel@tonic-gate 				}
38897c478bd9Sstevel@tonic-gate 			}
38907c478bd9Sstevel@tonic-gate 			/* Ensure specified filehandle matches */
3891d216dff5SRobert Mastors 			if (sp->rs_finfo->rf_vp != vp) {
38927c478bd9Sstevel@tonic-gate 				rfs4_state_rele_nounlock(sp);
38937c478bd9Sstevel@tonic-gate 				return (NFS4ERR_BAD_STATEID);
38947c478bd9Sstevel@tonic-gate 			}
38957c478bd9Sstevel@tonic-gate 
3896d216dff5SRobert Mastors 			if (sp->rs_owner->ro_need_confirm) {
38977c478bd9Sstevel@tonic-gate 				rfs4_state_rele_nounlock(sp);
38987c478bd9Sstevel@tonic-gate 				return (NFS4ERR_BAD_STATEID);
38997c478bd9Sstevel@tonic-gate 			}
39007c478bd9Sstevel@tonic-gate 
3901d216dff5SRobert Mastors 			if (sp->rs_closed == TRUE) {
39027c478bd9Sstevel@tonic-gate 				rfs4_state_rele_nounlock(sp);
39037c478bd9Sstevel@tonic-gate 				return (NFS4ERR_OLD_STATEID);
39047c478bd9Sstevel@tonic-gate 			}
39057c478bd9Sstevel@tonic-gate 
39067c478bd9Sstevel@tonic-gate 			if (do_access)
39077c478bd9Sstevel@tonic-gate 				stat = rfs4_state_has_access(sp, mode, vp);
39087c478bd9Sstevel@tonic-gate 			else
39097c478bd9Sstevel@tonic-gate 				stat = NFS4_OK;
39107c478bd9Sstevel@tonic-gate 
39117c478bd9Sstevel@tonic-gate 			/*
39127c478bd9Sstevel@tonic-gate 			 * Return whether this state has write
39137c478bd9Sstevel@tonic-gate 			 * delegation if desired
39147c478bd9Sstevel@tonic-gate 			 */
3915d216dff5SRobert Mastors 			if (deleg && (sp->rs_finfo->rf_dinfo.rd_dtype ==
3916d216dff5SRobert Mastors 			    OPEN_DELEGATE_WRITE))
39177c478bd9Sstevel@tonic-gate 				*deleg = TRUE;
39187c478bd9Sstevel@tonic-gate 
39197c478bd9Sstevel@tonic-gate 			/*
39207c478bd9Sstevel@tonic-gate 			 * We got a valid stateid, so we update the
39217c478bd9Sstevel@tonic-gate 			 * lease on the client. Ideally we would like
39227c478bd9Sstevel@tonic-gate 			 * to do this after the calling op succeeds,
39237c478bd9Sstevel@tonic-gate 			 * but for now this will be good
39247c478bd9Sstevel@tonic-gate 			 * enough. Callers of this routine are
39257c478bd9Sstevel@tonic-gate 			 * currently insulated from the state stuff.
39267c478bd9Sstevel@tonic-gate 			 */
3927d216dff5SRobert Mastors 			rfs4_update_lease(sp->rs_owner->ro_client);
39287c478bd9Sstevel@tonic-gate 
39297c478bd9Sstevel@tonic-gate 			/*
39307c478bd9Sstevel@tonic-gate 			 * If a delegation is present on this file and
39317c478bd9Sstevel@tonic-gate 			 * this is a WRITE, then update the lastwrite
39327c478bd9Sstevel@tonic-gate 			 * time to indicate that activity is present.
39337c478bd9Sstevel@tonic-gate 			 */
3934d216dff5SRobert Mastors 			if (sp->rs_finfo->rf_dinfo.rd_dtype ==
3935d216dff5SRobert Mastors 			    OPEN_DELEGATE_WRITE &&
3936ed57cab9Srg 			    mode == FWRITE) {
3937d216dff5SRobert Mastors 				sp->rs_finfo->rf_dinfo.rd_time_lastwrite =
3938ed57cab9Srg 				    gethrestime_sec();
39397c478bd9Sstevel@tonic-gate 			}
39407c478bd9Sstevel@tonic-gate 
3941*f44e1126SVitaliy Gusev 			/* Fill context for possible nbmand check */
3942*f44e1126SVitaliy Gusev 			if (ct != NULL && ct->cc_pid == 0) {
3943*f44e1126SVitaliy Gusev 				ct->cc_sysid =
3944*f44e1126SVitaliy Gusev 				    sp->rs_owner->ro_client->rc_sysidt;
3945*f44e1126SVitaliy Gusev 				ct->cc_pid =
3946*f44e1126SVitaliy Gusev 				    rfs4_dbe_getid(sp->rs_owner->ro_dbe);
3947*f44e1126SVitaliy Gusev 			}
3948*f44e1126SVitaliy Gusev 
39497c478bd9Sstevel@tonic-gate 			rfs4_state_rele_nounlock(sp);
39507c478bd9Sstevel@tonic-gate 
39517c478bd9Sstevel@tonic-gate 			return (stat);
39527c478bd9Sstevel@tonic-gate 		}
39537c478bd9Sstevel@tonic-gate 
39547c478bd9Sstevel@tonic-gate 		if (dsp != NULL) {
39557c478bd9Sstevel@tonic-gate 			/* Is associated server instance in its grace period? */
3956d216dff5SRobert Mastors 			if (rfs4_clnt_in_grace(dsp->rds_client)) {
39577c478bd9Sstevel@tonic-gate 				rfs4_deleg_state_rele(dsp);
39587c478bd9Sstevel@tonic-gate 				return (NFS4ERR_GRACE);
39597c478bd9Sstevel@tonic-gate 			}
3960*f44e1126SVitaliy Gusev 
3961*f44e1126SVitaliy Gusev 			stat = check_state_seqid(&dsp->rds_delegid, id, use_ss);
3962*f44e1126SVitaliy Gusev 			if (stat) {
39637c478bd9Sstevel@tonic-gate 				rfs4_deleg_state_rele(dsp);
3964*f44e1126SVitaliy Gusev 				return (stat);
39657c478bd9Sstevel@tonic-gate 			}
39667c478bd9Sstevel@tonic-gate 
39677c478bd9Sstevel@tonic-gate 			/* Ensure specified filehandle matches */
3968d216dff5SRobert Mastors 			if (dsp->rds_finfo->rf_vp != vp) {
39697c478bd9Sstevel@tonic-gate 				rfs4_deleg_state_rele(dsp);
39707c478bd9Sstevel@tonic-gate 				return (NFS4ERR_BAD_STATEID);
39717c478bd9Sstevel@tonic-gate 			}
39727c478bd9Sstevel@tonic-gate 			/*
39737c478bd9Sstevel@tonic-gate 			 * Return whether this state has write
39747c478bd9Sstevel@tonic-gate 			 * delegation if desired
39757c478bd9Sstevel@tonic-gate 			 */
3976d216dff5SRobert Mastors 			if (deleg && (dsp->rds_finfo->rf_dinfo.rd_dtype ==
3977d216dff5SRobert Mastors 			    OPEN_DELEGATE_WRITE))
39787c478bd9Sstevel@tonic-gate 				*deleg = TRUE;
39797c478bd9Sstevel@tonic-gate 
3980d216dff5SRobert Mastors 			rfs4_update_lease(dsp->rds_client);
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate 			/*
39837c478bd9Sstevel@tonic-gate 			 * If a delegation is present on this file and
39847c478bd9Sstevel@tonic-gate 			 * this is a WRITE, then update the lastwrite
39857c478bd9Sstevel@tonic-gate 			 * time to indicate that activity is present.
39867c478bd9Sstevel@tonic-gate 			 */
3987d216dff5SRobert Mastors 			if (dsp->rds_finfo->rf_dinfo.rd_dtype ==
3988d216dff5SRobert Mastors 			    OPEN_DELEGATE_WRITE && mode == FWRITE) {
3989d216dff5SRobert Mastors 				dsp->rds_finfo->rf_dinfo.rd_time_lastwrite =
3990ed57cab9Srg 				    gethrestime_sec();
39917c478bd9Sstevel@tonic-gate 			}
39927c478bd9Sstevel@tonic-gate 
39937c478bd9Sstevel@tonic-gate 			/*
39947c478bd9Sstevel@tonic-gate 			 * XXX - what happens if this is a WRITE and the
39957c478bd9Sstevel@tonic-gate 			 * delegation type of for READ.
39967c478bd9Sstevel@tonic-gate 			 */
39977c478bd9Sstevel@tonic-gate 			rfs4_deleg_state_rele(dsp);
39987c478bd9Sstevel@tonic-gate 
39997c478bd9Sstevel@tonic-gate 			return (stat);
40007c478bd9Sstevel@tonic-gate 		}
40017c478bd9Sstevel@tonic-gate 		/*
40027c478bd9Sstevel@tonic-gate 		 * If we got this far, something bad happened
40037c478bd9Sstevel@tonic-gate 		 */
40047c478bd9Sstevel@tonic-gate 		return (NFS4ERR_BAD_STATEID);
40057c478bd9Sstevel@tonic-gate 	}
40067c478bd9Sstevel@tonic-gate }
40077c478bd9Sstevel@tonic-gate 
40087c478bd9Sstevel@tonic-gate 
40097c478bd9Sstevel@tonic-gate /*
40107c478bd9Sstevel@tonic-gate  * This is a special function in that for the file struct provided the
40117c478bd9Sstevel@tonic-gate  * server wants to remove/close all current state associated with the
40127c478bd9Sstevel@tonic-gate  * file.  The prime use of this would be with OP_REMOVE to force the
40137c478bd9Sstevel@tonic-gate  * release of state and particularly of file locks.
40147c478bd9Sstevel@tonic-gate  *
40157c478bd9Sstevel@tonic-gate  * There is an assumption that there is no delegations outstanding on
40167c478bd9Sstevel@tonic-gate  * this file at this point.  The caller should have waited for those
40177c478bd9Sstevel@tonic-gate  * to be returned or revoked.
40187c478bd9Sstevel@tonic-gate  */
40197c478bd9Sstevel@tonic-gate void
rfs4_close_all_state(rfs4_file_t * fp)40207c478bd9Sstevel@tonic-gate rfs4_close_all_state(rfs4_file_t *fp)
40217c478bd9Sstevel@tonic-gate {
40227c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp;
40237c478bd9Sstevel@tonic-gate 
4024d216dff5SRobert Mastors 	rfs4_dbe_lock(fp->rf_dbe);
40257c478bd9Sstevel@tonic-gate 
40267c478bd9Sstevel@tonic-gate #ifdef DEBUG
40277c478bd9Sstevel@tonic-gate 	/* only applies when server is handing out delegations */
40280dfe541eSEvan Layton 	if (nfs4_get_deleg_policy() != SRV_NEVER_DELEGATE)
4029d216dff5SRobert Mastors 		ASSERT(fp->rf_dinfo.rd_hold_grant > 0);
40307c478bd9Sstevel@tonic-gate #endif
40317c478bd9Sstevel@tonic-gate 
40327c478bd9Sstevel@tonic-gate 	/* No delegations for this file */
4033d216dff5SRobert Mastors 	ASSERT(list_is_empty(&fp->rf_delegstatelist));
40347c478bd9Sstevel@tonic-gate 
40357c478bd9Sstevel@tonic-gate 	/* Make sure that it can not be found */
4036d216dff5SRobert Mastors 	rfs4_dbe_invalidate(fp->rf_dbe);
40377c478bd9Sstevel@tonic-gate 
4038d216dff5SRobert Mastors 	if (fp->rf_vp == NULL) {
4039d216dff5SRobert Mastors 		rfs4_dbe_unlock(fp->rf_dbe);
40407c478bd9Sstevel@tonic-gate 		return;
40417c478bd9Sstevel@tonic-gate 	}
4042d216dff5SRobert Mastors 	rfs4_dbe_unlock(fp->rf_dbe);
40437c478bd9Sstevel@tonic-gate 
40447c478bd9Sstevel@tonic-gate 	/*
40457c478bd9Sstevel@tonic-gate 	 * Hold as writer to prevent other server threads from
40467c478bd9Sstevel@tonic-gate 	 * processing requests related to the file while all state is
40477c478bd9Sstevel@tonic-gate 	 * being removed.
40487c478bd9Sstevel@tonic-gate 	 */
4049d216dff5SRobert Mastors 	rw_enter(&fp->rf_file_rwlock, RW_WRITER);
40507c478bd9Sstevel@tonic-gate 
40517c478bd9Sstevel@tonic-gate 	/* Remove ALL state from the file */
4052bd3561fbSToomas Soome 	while ((sp = rfs4_findstate_by_file(fp)) != NULL) {
40537c478bd9Sstevel@tonic-gate 		rfs4_state_close(sp, FALSE, FALSE, CRED());
40547c478bd9Sstevel@tonic-gate 		rfs4_state_rele_nounlock(sp);
40557c478bd9Sstevel@tonic-gate 	}
40567c478bd9Sstevel@tonic-gate 
40577c478bd9Sstevel@tonic-gate 	/*
40587c478bd9Sstevel@tonic-gate 	 * This is only safe since there are no further references to
40597c478bd9Sstevel@tonic-gate 	 * the file.
40607c478bd9Sstevel@tonic-gate 	 */
4061d216dff5SRobert Mastors 	rfs4_dbe_lock(fp->rf_dbe);
4062d216dff5SRobert Mastors 	if (fp->rf_vp) {
4063d216dff5SRobert Mastors 		vnode_t *vp = fp->rf_vp;
40641b300de9Sjwahlig 
4065d216dff5SRobert Mastors 		mutex_enter(&vp->v_vsd_lock);
40661b300de9Sjwahlig 		(void) vsd_set(vp, nfs4_srv_vkey, NULL);
4067d216dff5SRobert Mastors 		mutex_exit(&vp->v_vsd_lock);
40681b300de9Sjwahlig 		VN_RELE(vp);
4069d216dff5SRobert Mastors 		fp->rf_vp = NULL;
40707c478bd9Sstevel@tonic-gate 	}
4071d216dff5SRobert Mastors 	rfs4_dbe_unlock(fp->rf_dbe);
40727c478bd9Sstevel@tonic-gate 
40737c478bd9Sstevel@tonic-gate 	/* Finally let other references to proceed */
4074d216dff5SRobert Mastors 	rw_exit(&fp->rf_file_rwlock);
40757c478bd9Sstevel@tonic-gate }
40767c478bd9Sstevel@tonic-gate 
40777c478bd9Sstevel@tonic-gate /*
40787c478bd9Sstevel@tonic-gate  * This function is used as a target for the rfs4_dbe_walk() call
40797c478bd9Sstevel@tonic-gate  * below.  The purpose of this function is to see if the
40807c478bd9Sstevel@tonic-gate  * lockowner_state refers to a file that resides within the exportinfo
40817c478bd9Sstevel@tonic-gate  * export.  If so, then remove the lock_owner state (file locks and
40827c478bd9Sstevel@tonic-gate  * share "locks") for this object since the intent is the server is
40837c478bd9Sstevel@tonic-gate  * unexporting the specified directory.  Be sure to invalidate the
40847c478bd9Sstevel@tonic-gate  * object after the state has been released
40857c478bd9Sstevel@tonic-gate  */
40867c478bd9Sstevel@tonic-gate static void
rfs4_lo_state_walk_callout(rfs4_entry_t u_entry,void * e)40877c478bd9Sstevel@tonic-gate rfs4_lo_state_walk_callout(rfs4_entry_t u_entry, void *e)
40887c478bd9Sstevel@tonic-gate {
40897c478bd9Sstevel@tonic-gate 	rfs4_lo_state_t *lsp = (rfs4_lo_state_t *)u_entry;
40907c478bd9Sstevel@tonic-gate 	struct exportinfo *exi = (struct exportinfo *)e;
4091b096b66cSnr 	nfs_fh4_fmt_t   fhfmt4, *exi_fhp, *finfo_fhp;
4092b096b66cSnr 	fhandle_t *efhp;
4093b096b66cSnr 
4094b096b66cSnr 	efhp = (fhandle_t *)&exi->exi_fh;
4095b096b66cSnr 	exi_fhp = (nfs_fh4_fmt_t *)&fhfmt4;
4096b096b66cSnr 
4097b096b66cSnr 	FH_TO_FMT4(efhp, exi_fhp);
40987c478bd9Sstevel@tonic-gate 
4099d216dff5SRobert Mastors 	finfo_fhp = (nfs_fh4_fmt_t *)lsp->rls_state->rs_finfo->
4100d216dff5SRobert Mastors 	    rf_filehandle.nfs_fh4_val;
41017c478bd9Sstevel@tonic-gate 
41027c478bd9Sstevel@tonic-gate 	if (EQFSID(&finfo_fhp->fh4_fsid, &exi_fhp->fh4_fsid) &&
41037c478bd9Sstevel@tonic-gate 	    bcmp(&finfo_fhp->fh4_xdata, &exi_fhp->fh4_xdata,
4104ed57cab9Srg 	    exi_fhp->fh4_xlen) == 0) {
4105d216dff5SRobert Mastors 		rfs4_state_close(lsp->rls_state, FALSE, FALSE, CRED());
4106d216dff5SRobert Mastors 		rfs4_dbe_invalidate(lsp->rls_dbe);
4107d216dff5SRobert Mastors 		rfs4_dbe_invalidate(lsp->rls_state->rs_dbe);
41087c478bd9Sstevel@tonic-gate 	}
41097c478bd9Sstevel@tonic-gate }
41107c478bd9Sstevel@tonic-gate 
41117c478bd9Sstevel@tonic-gate /*
41127c478bd9Sstevel@tonic-gate  * This function is used as a target for the rfs4_dbe_walk() call
41137c478bd9Sstevel@tonic-gate  * below.  The purpose of this function is to see if the state refers
41147c478bd9Sstevel@tonic-gate  * to a file that resides within the exportinfo export.  If so, then
41157c478bd9Sstevel@tonic-gate  * remove the open state for this object since the intent is the
41167c478bd9Sstevel@tonic-gate  * server is unexporting the specified directory.  The main result for
41177c478bd9Sstevel@tonic-gate  * this type of entry is to invalidate it such it will not be found in
41187c478bd9Sstevel@tonic-gate  * the future.
41197c478bd9Sstevel@tonic-gate  */
41207c478bd9Sstevel@tonic-gate static void
rfs4_state_walk_callout(rfs4_entry_t u_entry,void * e)41217c478bd9Sstevel@tonic-gate rfs4_state_walk_callout(rfs4_entry_t u_entry, void *e)
41227c478bd9Sstevel@tonic-gate {
41237c478bd9Sstevel@tonic-gate 	rfs4_state_t *sp = (rfs4_state_t *)u_entry;
41247c478bd9Sstevel@tonic-gate 	struct exportinfo *exi = (struct exportinfo *)e;
4125b096b66cSnr 	nfs_fh4_fmt_t   fhfmt4, *exi_fhp, *finfo_fhp;
4126b096b66cSnr 	fhandle_t *efhp;
4127b096b66cSnr 
4128b096b66cSnr 	efhp = (fhandle_t *)&exi->exi_fh;
4129b096b66cSnr 	exi_fhp = (nfs_fh4_fmt_t *)&fhfmt4;
4130b096b66cSnr 
4131b096b66cSnr 	FH_TO_FMT4(efhp, exi_fhp);
41327c478bd9Sstevel@tonic-gate 
41337c478bd9Sstevel@tonic-gate 	finfo_fhp =
4134d216dff5SRobert Mastors 	    (nfs_fh4_fmt_t *)sp->rs_finfo->rf_filehandle.nfs_fh4_val;
41357c478bd9Sstevel@tonic-gate 
41367c478bd9Sstevel@tonic-gate 	if (EQFSID(&finfo_fhp->fh4_fsid, &exi_fhp->fh4_fsid) &&
41377c478bd9Sstevel@tonic-gate 	    bcmp(&finfo_fhp->fh4_xdata, &exi_fhp->fh4_xdata,
4138ed57cab9Srg 	    exi_fhp->fh4_xlen) == 0) {
41397c478bd9Sstevel@tonic-gate 		rfs4_state_close(sp, TRUE, FALSE, CRED());
4140d216dff5SRobert Mastors 		rfs4_dbe_invalidate(sp->rs_dbe);
41417c478bd9Sstevel@tonic-gate 	}
41427c478bd9Sstevel@tonic-gate }
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate /*
41457c478bd9Sstevel@tonic-gate  * This function is used as a target for the rfs4_dbe_walk() call
41467c478bd9Sstevel@tonic-gate  * below.  The purpose of this function is to see if the state refers
41477c478bd9Sstevel@tonic-gate  * to a file that resides within the exportinfo export.  If so, then
41487c478bd9Sstevel@tonic-gate  * remove the deleg state for this object since the intent is the
41497c478bd9Sstevel@tonic-gate  * server is unexporting the specified directory.  The main result for
41507c478bd9Sstevel@tonic-gate  * this type of entry is to invalidate it such it will not be found in
41517c478bd9Sstevel@tonic-gate  * the future.
41527c478bd9Sstevel@tonic-gate  */
41537c478bd9Sstevel@tonic-gate static void
rfs4_deleg_state_walk_callout(rfs4_entry_t u_entry,void * e)41547c478bd9Sstevel@tonic-gate rfs4_deleg_state_walk_callout(rfs4_entry_t u_entry, void *e)
41557c478bd9Sstevel@tonic-gate {
41567c478bd9Sstevel@tonic-gate 	rfs4_deleg_state_t *dsp = (rfs4_deleg_state_t *)u_entry;
41577c478bd9Sstevel@tonic-gate 	struct exportinfo *exi = (struct exportinfo *)e;
4158b096b66cSnr 	nfs_fh4_fmt_t   fhfmt4, *exi_fhp, *finfo_fhp;
4159b096b66cSnr 	fhandle_t *efhp;
4160b096b66cSnr 
4161b096b66cSnr 	efhp = (fhandle_t *)&exi->exi_fh;
4162b096b66cSnr 	exi_fhp = (nfs_fh4_fmt_t *)&fhfmt4;
4163b096b66cSnr 
4164b096b66cSnr 	FH_TO_FMT4(efhp, exi_fhp);
41657c478bd9Sstevel@tonic-gate 
41667c478bd9Sstevel@tonic-gate 	finfo_fhp =
4167d216dff5SRobert Mastors 	    (nfs_fh4_fmt_t *)dsp->rds_finfo->rf_filehandle.nfs_fh4_val;
41687c478bd9Sstevel@tonic-gate 
41697c478bd9Sstevel@tonic-gate 	if (EQFSID(&finfo_fhp->fh4_fsid, &exi_fhp->fh4_fsid) &&
41707c478bd9Sstevel@tonic-gate 	    bcmp(&finfo_fhp->fh4_xdata, &exi_fhp->fh4_xdata,
4171ed57cab9Srg 	    exi_fhp->fh4_xlen) == 0) {
4172d216dff5SRobert Mastors 		rfs4_dbe_invalidate(dsp->rds_dbe);
41737c478bd9Sstevel@tonic-gate 	}
41747c478bd9Sstevel@tonic-gate }
41757c478bd9Sstevel@tonic-gate 
41767c478bd9Sstevel@tonic-gate /*
41777c478bd9Sstevel@tonic-gate  * This function is used as a target for the rfs4_dbe_walk() call
41787c478bd9Sstevel@tonic-gate  * below.  The purpose of this function is to see if the state refers
41797c478bd9Sstevel@tonic-gate  * to a file that resides within the exportinfo export.  If so, then
41807c478bd9Sstevel@tonic-gate  * release vnode hold for this object since the intent is the server
41817c478bd9Sstevel@tonic-gate  * is unexporting the specified directory.  Invalidation will prevent
41827c478bd9Sstevel@tonic-gate  * this struct from being found in the future.
41837c478bd9Sstevel@tonic-gate  */
41847c478bd9Sstevel@tonic-gate static void
rfs4_file_walk_callout(rfs4_entry_t u_entry,void * e)41857c478bd9Sstevel@tonic-gate rfs4_file_walk_callout(rfs4_entry_t u_entry, void *e)
41867c478bd9Sstevel@tonic-gate {
41877c478bd9Sstevel@tonic-gate 	rfs4_file_t *fp = (rfs4_file_t *)u_entry;
41887c478bd9Sstevel@tonic-gate 	struct exportinfo *exi = (struct exportinfo *)e;
4189b096b66cSnr 	nfs_fh4_fmt_t   fhfmt4, *exi_fhp, *finfo_fhp;
4190b096b66cSnr 	fhandle_t *efhp;
4191b096b66cSnr 
4192b096b66cSnr 	efhp = (fhandle_t *)&exi->exi_fh;
4193b096b66cSnr 	exi_fhp = (nfs_fh4_fmt_t *)&fhfmt4;
4194b096b66cSnr 
4195b096b66cSnr 	FH_TO_FMT4(efhp, exi_fhp);
41967c478bd9Sstevel@tonic-gate 
4197d216dff5SRobert Mastors 	finfo_fhp = (nfs_fh4_fmt_t *)fp->rf_filehandle.nfs_fh4_val;
41987c478bd9Sstevel@tonic-gate 
41997c478bd9Sstevel@tonic-gate 	if (EQFSID(&finfo_fhp->fh4_fsid, &exi_fhp->fh4_fsid) &&
42007c478bd9Sstevel@tonic-gate 	    bcmp(&finfo_fhp->fh4_xdata, &exi_fhp->fh4_xdata,
4201ed57cab9Srg 	    exi_fhp->fh4_xlen) == 0) {
4202d216dff5SRobert Mastors 		if (fp->rf_vp) {
4203d216dff5SRobert Mastors 			vnode_t *vp = fp->rf_vp;
4204bb972d76Sjwahlig 
4205da6c28aaSamw 			/*
4206da6c28aaSamw 			 * don't leak monitors and remove the reference
4207da6c28aaSamw 			 * put on the vnode when the delegation was granted.
4208da6c28aaSamw 			 */
4209d216dff5SRobert Mastors 			if (fp->rf_dinfo.rd_dtype == OPEN_DELEGATE_READ) {
4210bb972d76Sjwahlig 				(void) fem_uninstall(vp, deleg_rdops,
4211ed57cab9Srg 				    (void *)fp);
4212da6c28aaSamw 				vn_open_downgrade(vp, FREAD);
4213d216dff5SRobert Mastors 			} else if (fp->rf_dinfo.rd_dtype ==
4214d216dff5SRobert Mastors 			    OPEN_DELEGATE_WRITE) {
4215bb972d76Sjwahlig 				(void) fem_uninstall(vp, deleg_wrops,
4216ed57cab9Srg 				    (void *)fp);
4217da6c28aaSamw 				vn_open_downgrade(vp, FREAD|FWRITE);
4218da6c28aaSamw 			}
4219d216dff5SRobert Mastors 			mutex_enter(&vp->v_vsd_lock);
4220bb972d76Sjwahlig 			(void) vsd_set(vp, nfs4_srv_vkey, NULL);
4221d216dff5SRobert Mastors 			mutex_exit(&vp->v_vsd_lock);
4222bb972d76Sjwahlig 			VN_RELE(vp);
4223d216dff5SRobert Mastors 			fp->rf_vp = NULL;
42247c478bd9Sstevel@tonic-gate 		}
4225d216dff5SRobert Mastors 		rfs4_dbe_invalidate(fp->rf_dbe);
42267c478bd9Sstevel@tonic-gate 	}
42277c478bd9Sstevel@tonic-gate }
42287c478bd9Sstevel@tonic-gate 
42297c478bd9Sstevel@tonic-gate /*
42307c478bd9Sstevel@tonic-gate  * Given a directory that is being unexported, cleanup/release all
42317c478bd9Sstevel@tonic-gate  * state in the server that refers to objects residing underneath this
42327c478bd9Sstevel@tonic-gate  * particular export.  The ordering of the release is important.
42337c478bd9Sstevel@tonic-gate  * Lock_owner, then state and then file.
42340dfe541eSEvan Layton  *
42350dfe541eSEvan Layton  * NFS zones note: nfs_export.c:unexport() calls this from a
42360dfe541eSEvan Layton  * thread in the global zone for NGZ data structures, so we
42370dfe541eSEvan Layton  * CANNOT use zone_getspecific anywhere in this code path.
42387c478bd9Sstevel@tonic-gate  */
42397c478bd9Sstevel@tonic-gate void
rfs4_clean_state_exi(nfs_export_t * ne,struct exportinfo * exi)42400dfe541eSEvan Layton rfs4_clean_state_exi(nfs_export_t *ne, struct exportinfo *exi)
42417c478bd9Sstevel@tonic-gate {
42420dfe541eSEvan Layton 	nfs_globals_t *ng;
42430dfe541eSEvan Layton 	nfs4_srv_t *nsrv4;
42440dfe541eSEvan Layton 
42450dfe541eSEvan Layton 	ng = ne->ne_globals;
42460dfe541eSEvan Layton 	ASSERT(ng->nfs_zoneid == exi->exi_zoneid);
42470dfe541eSEvan Layton 	nsrv4 = ng->nfs4_srv;
42480dfe541eSEvan Layton 
42490dfe541eSEvan Layton 	mutex_enter(&nsrv4->state_lock);
42507c478bd9Sstevel@tonic-gate 
42510dfe541eSEvan Layton 	if (nsrv4->nfs4_server_state == NULL) {
42520dfe541eSEvan Layton 		mutex_exit(&nsrv4->state_lock);
42537c478bd9Sstevel@tonic-gate 		return;
42547c478bd9Sstevel@tonic-gate 	}
42557c478bd9Sstevel@tonic-gate 
42560dfe541eSEvan Layton 	rfs4_dbe_walk(nsrv4->rfs4_lo_state_tab,
42570dfe541eSEvan Layton 	    rfs4_lo_state_walk_callout, exi);
42580dfe541eSEvan Layton 	rfs4_dbe_walk(nsrv4->rfs4_state_tab, rfs4_state_walk_callout, exi);
42590dfe541eSEvan Layton 	rfs4_dbe_walk(nsrv4->rfs4_deleg_state_tab,
42600dfe541eSEvan Layton 	    rfs4_deleg_state_walk_callout, exi);
42610dfe541eSEvan Layton 	rfs4_dbe_walk(nsrv4->rfs4_file_tab, rfs4_file_walk_callout, exi);
42627c478bd9Sstevel@tonic-gate 
42630dfe541eSEvan Layton 	mutex_exit(&nsrv4->state_lock);
42647c478bd9Sstevel@tonic-gate }
4265