xref: /onnv-gate/usr/src/uts/common/fs/nfs/nfs4_client_state.c (revision 7981:7bc14f7bfa37)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53057Sjwahlig  * Common Development and Distribution License (the "License").
63057Sjwahlig  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
227902SNagakiran.Rajashekar@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <nfs/nfs4_clnt.h>
310Sstevel@tonic-gate #include <nfs/rnode4.h>
320Sstevel@tonic-gate #include <sys/systm.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/atomic.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate static void	nfs4_free_open_owner(nfs4_open_owner_t *, mntinfo4_t *);
370Sstevel@tonic-gate static nfs4_open_owner_t *find_freed_open_owner(cred_t *,
380Sstevel@tonic-gate 				nfs4_oo_hash_bucket_t *, mntinfo4_t *);
390Sstevel@tonic-gate static open_delegation_type4 get_dtype(rnode4_t *);
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #ifdef DEBUG
420Sstevel@tonic-gate int nfs4_client_foo_debug = 0x0;
430Sstevel@tonic-gate int nfs4_client_open_dg = 0x0;
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * If this is non-zero, the lockowner and openowner seqid sync primitives
460Sstevel@tonic-gate  * will intermittently return errors.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate static int seqid_sync_faults = 0;
490Sstevel@tonic-gate #endif
500Sstevel@tonic-gate 
510Sstevel@tonic-gate stateid4 clnt_special0 = {
520Sstevel@tonic-gate 	0,
530Sstevel@tonic-gate 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
540Sstevel@tonic-gate };
550Sstevel@tonic-gate 
560Sstevel@tonic-gate stateid4 clnt_special1 = {
570Sstevel@tonic-gate 	0xffffffff,
580Sstevel@tonic-gate 	{
590Sstevel@tonic-gate 		(char)0xff, (char)0xff, (char)0xff, (char)0xff,
600Sstevel@tonic-gate 		(char)0xff, (char)0xff, (char)0xff, (char)0xff,
610Sstevel@tonic-gate 		(char)0xff, (char)0xff, (char)0xff, (char)0xff
620Sstevel@tonic-gate 	}
630Sstevel@tonic-gate };
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /* finds hash bucket and locks it */
660Sstevel@tonic-gate static nfs4_oo_hash_bucket_t *
lock_bucket(cred_t * cr,mntinfo4_t * mi)670Sstevel@tonic-gate lock_bucket(cred_t *cr, mntinfo4_t *mi)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	nfs4_oo_hash_bucket_t *bucketp;
700Sstevel@tonic-gate 	uint32_t hash_key;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	hash_key = (uint32_t)(crgetuid(cr) + crgetruid(cr))
737902SNagakiran.Rajashekar@Sun.COM 	    % NFS4_NUM_OO_BUCKETS;
740Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE, "lock_bucket: "
757902SNagakiran.Rajashekar@Sun.COM 	    "hash_key %d for cred %p", hash_key, (void*)cr));
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 	ASSERT(hash_key >= 0 && hash_key < NFS4_NUM_OO_BUCKETS);
780Sstevel@tonic-gate 	ASSERT(mi != NULL);
790Sstevel@tonic-gate 	ASSERT(mutex_owned(&mi->mi_lock));
800Sstevel@tonic-gate 
810Sstevel@tonic-gate 	bucketp = &(mi->mi_oo_list[hash_key]);
820Sstevel@tonic-gate 	mutex_enter(&bucketp->b_lock);
830Sstevel@tonic-gate 	return (bucketp);
840Sstevel@tonic-gate }
850Sstevel@tonic-gate 
860Sstevel@tonic-gate /* unlocks hash bucket pointed by bucket_ptr */
870Sstevel@tonic-gate static void
unlock_bucket(nfs4_oo_hash_bucket_t * bucketp)880Sstevel@tonic-gate unlock_bucket(nfs4_oo_hash_bucket_t *bucketp)
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	mutex_exit(&bucketp->b_lock);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*
940Sstevel@tonic-gate  * Removes the lock owner from the rnode's lock_owners list and frees the
950Sstevel@tonic-gate  * corresponding reference.
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate void
nfs4_rnode_remove_lock_owner(rnode4_t * rp,nfs4_lock_owner_t * lop)980Sstevel@tonic-gate nfs4_rnode_remove_lock_owner(rnode4_t *rp, nfs4_lock_owner_t *lop)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
1017902SNagakiran.Rajashekar@Sun.COM 	    "nfs4_rnode_remove_lock_owner"));
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	mutex_enter(&rp->r_statev4_lock);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	if (lop->lo_next_rnode == NULL) {
1060Sstevel@tonic-gate 		/* already removed from list */
1070Sstevel@tonic-gate 		mutex_exit(&rp->r_statev4_lock);
1080Sstevel@tonic-gate 		return;
1090Sstevel@tonic-gate 	}
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	ASSERT(lop->lo_prev_rnode != NULL);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	lop->lo_prev_rnode->lo_next_rnode = lop->lo_next_rnode;
1140Sstevel@tonic-gate 	lop->lo_next_rnode->lo_prev_rnode = lop->lo_prev_rnode;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	lop->lo_next_rnode = lop->lo_prev_rnode = NULL;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	mutex_exit(&rp->r_statev4_lock);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	/*
1210Sstevel@tonic-gate 	 * This would be an appropriate place for
1220Sstevel@tonic-gate 	 * RELEASE_LOCKOWNER.  For now, this is overkill
1230Sstevel@tonic-gate 	 * because in the common case, close is going to
1240Sstevel@tonic-gate 	 * release any lockowners anyway.
1250Sstevel@tonic-gate 	 */
1260Sstevel@tonic-gate 	lock_owner_rele(lop);
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate  * Remove all lock owners from the rnode's lock_owners list.  Frees up
1310Sstevel@tonic-gate  * their references from the list.
1320Sstevel@tonic-gate  */
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate void
nfs4_flush_lock_owners(rnode4_t * rp)1350Sstevel@tonic-gate nfs4_flush_lock_owners(rnode4_t *rp)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate 	nfs4_lock_owner_t *lop;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	mutex_enter(&rp->r_statev4_lock);
1400Sstevel@tonic-gate 	while (rp->r_lo_head.lo_next_rnode != &rp->r_lo_head) {
1410Sstevel@tonic-gate 		lop = rp->r_lo_head.lo_next_rnode;
1420Sstevel@tonic-gate 		lop->lo_prev_rnode->lo_next_rnode = lop->lo_next_rnode;
1430Sstevel@tonic-gate 		lop->lo_next_rnode->lo_prev_rnode = lop->lo_prev_rnode;
1440Sstevel@tonic-gate 		lop->lo_next_rnode = lop->lo_prev_rnode = NULL;
1450Sstevel@tonic-gate 		lock_owner_rele(lop);
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 	mutex_exit(&rp->r_statev4_lock);
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate void
nfs4_clear_open_streams(rnode4_t * rp)1510Sstevel@tonic-gate nfs4_clear_open_streams(rnode4_t *rp)
1520Sstevel@tonic-gate {
1530Sstevel@tonic-gate 	nfs4_open_stream_t *osp;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	mutex_enter(&rp->r_os_lock);
1560Sstevel@tonic-gate 	while ((osp = list_head(&rp->r_open_streams)) != NULL) {
1570Sstevel@tonic-gate 		open_owner_rele(osp->os_open_owner);
1580Sstevel@tonic-gate 		list_remove(&rp->r_open_streams, osp);
1590Sstevel@tonic-gate 		mutex_destroy(&osp->os_sync_lock);
1600Sstevel@tonic-gate 		osp->os_open_owner = NULL;
1610Sstevel@tonic-gate 		kmem_free(osp, sizeof (*osp));
1620Sstevel@tonic-gate 	}
1630Sstevel@tonic-gate 	mutex_exit(&rp->r_os_lock);
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate void
open_owner_hold(nfs4_open_owner_t * oop)1670Sstevel@tonic-gate open_owner_hold(nfs4_open_owner_t *oop)
1680Sstevel@tonic-gate {
1690Sstevel@tonic-gate 	mutex_enter(&oop->oo_lock);
1700Sstevel@tonic-gate 	oop->oo_ref_count++;
1710Sstevel@tonic-gate 	mutex_exit(&oop->oo_lock);
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate  * Frees the open owner if the ref count hits zero.
1760Sstevel@tonic-gate  */
1770Sstevel@tonic-gate void
open_owner_rele(nfs4_open_owner_t * oop)1780Sstevel@tonic-gate open_owner_rele(nfs4_open_owner_t *oop)
1790Sstevel@tonic-gate {
1800Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
1817902SNagakiran.Rajashekar@Sun.COM 	    "open_owner_rele"));
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 	mutex_enter(&oop->oo_lock);
1840Sstevel@tonic-gate 	oop->oo_ref_count--;
1850Sstevel@tonic-gate 	if (oop->oo_ref_count == 0) {
1860Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
1877902SNagakiran.Rajashekar@Sun.COM 		    "open_owner_rele: freeing open owner"));
1880Sstevel@tonic-gate 		oop->oo_valid = 0;
1890Sstevel@tonic-gate 		mutex_exit(&oop->oo_lock);
1900Sstevel@tonic-gate 		/*
1910Sstevel@tonic-gate 		 * Ok, we don't destroy the open owner, nor do we put it on
1920Sstevel@tonic-gate 		 * the mntinfo4's free list just yet.  We are lazy about it
1930Sstevel@tonic-gate 		 * and let callers to find_open_owner() do that to keep locking
1940Sstevel@tonic-gate 		 * simple.
1950Sstevel@tonic-gate 		 */
1960Sstevel@tonic-gate 	} else {
1970Sstevel@tonic-gate 		mutex_exit(&oop->oo_lock);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate void
open_stream_hold(nfs4_open_stream_t * osp)2020Sstevel@tonic-gate open_stream_hold(nfs4_open_stream_t *osp)
2030Sstevel@tonic-gate {
2040Sstevel@tonic-gate 	mutex_enter(&osp->os_sync_lock);
2050Sstevel@tonic-gate 	osp->os_ref_count++;
2060Sstevel@tonic-gate 	mutex_exit(&osp->os_sync_lock);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate  * Frees the open stream and removes it from the rnode4's open streams list if
2110Sstevel@tonic-gate  * the ref count drops to zero.
2120Sstevel@tonic-gate  */
2130Sstevel@tonic-gate void
open_stream_rele(nfs4_open_stream_t * osp,rnode4_t * rp)2140Sstevel@tonic-gate open_stream_rele(nfs4_open_stream_t *osp, rnode4_t *rp)
2150Sstevel@tonic-gate {
2160Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
2177902SNagakiran.Rajashekar@Sun.COM 	    "open_stream_rele"));
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	ASSERT(!mutex_owned(&rp->r_os_lock));
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	mutex_enter(&osp->os_sync_lock);
2220Sstevel@tonic-gate 	ASSERT(osp->os_ref_count > 0);
2230Sstevel@tonic-gate 	osp->os_ref_count--;
2240Sstevel@tonic-gate 	if (osp->os_ref_count == 0) {
2250Sstevel@tonic-gate 		nfs4_open_owner_t *tmp_oop;
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
2287902SNagakiran.Rajashekar@Sun.COM 		    "open_stream_rele: freeing open stream"));
2290Sstevel@tonic-gate 		osp->os_valid = 0;
2300Sstevel@tonic-gate 		tmp_oop = osp->os_open_owner;
2310Sstevel@tonic-gate 		mutex_exit(&osp->os_sync_lock);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 		/* now see if we need to destroy the open owner */
2340Sstevel@tonic-gate 		open_owner_rele(tmp_oop);
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 		mutex_enter(&rp->r_os_lock);
2370Sstevel@tonic-gate 		list_remove(&rp->r_open_streams, osp);
2380Sstevel@tonic-gate 		mutex_exit(&rp->r_os_lock);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 		/* free up osp */
2410Sstevel@tonic-gate 		mutex_destroy(&osp->os_sync_lock);
2420Sstevel@tonic-gate 		osp->os_open_owner = NULL;
2430Sstevel@tonic-gate 		kmem_free(osp, sizeof (*osp));
2440Sstevel@tonic-gate 	} else {
2450Sstevel@tonic-gate 		mutex_exit(&osp->os_sync_lock);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate 
2490Sstevel@tonic-gate void
lock_owner_hold(nfs4_lock_owner_t * lop)2500Sstevel@tonic-gate lock_owner_hold(nfs4_lock_owner_t *lop)
2510Sstevel@tonic-gate {
2520Sstevel@tonic-gate 	mutex_enter(&lop->lo_lock);
2530Sstevel@tonic-gate 	lop->lo_ref_count++;
2540Sstevel@tonic-gate 	mutex_exit(&lop->lo_lock);
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate  * Frees the lock owner if the ref count hits zero and
2590Sstevel@tonic-gate  * the structure no longer has no locks.
2600Sstevel@tonic-gate  */
2610Sstevel@tonic-gate void
lock_owner_rele(nfs4_lock_owner_t * lop)2620Sstevel@tonic-gate lock_owner_rele(nfs4_lock_owner_t *lop)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
2657902SNagakiran.Rajashekar@Sun.COM 	    "lock_owner_rele"));
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	mutex_enter(&lop->lo_lock);
2680Sstevel@tonic-gate 	lop->lo_ref_count--;
2690Sstevel@tonic-gate 	if (lop->lo_ref_count == 0) {
2700Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
2717902SNagakiran.Rajashekar@Sun.COM 		    "lock_owner_rele: freeing lock owner: "
2727902SNagakiran.Rajashekar@Sun.COM 		    "%x", lop->lo_pid));
2730Sstevel@tonic-gate 		lop->lo_valid = 0;
2740Sstevel@tonic-gate 		/*
2750Sstevel@tonic-gate 		 * If there are no references, the lock_owner should
2760Sstevel@tonic-gate 		 * already be off the rnode's list.
2770Sstevel@tonic-gate 		 */
2780Sstevel@tonic-gate 		ASSERT(lop->lo_next_rnode == NULL);
2790Sstevel@tonic-gate 		ASSERT(lop->lo_prev_rnode == NULL);
2800Sstevel@tonic-gate 		ASSERT(!(lop->lo_flags & NFS4_LOCK_SEQID_INUSE));
2810Sstevel@tonic-gate 		ASSERT(lop->lo_seqid_holder == NULL);
2820Sstevel@tonic-gate 		mutex_exit(&lop->lo_lock);
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 		/* free up lop */
2850Sstevel@tonic-gate 		cv_destroy(&lop->lo_cv_seqid_sync);
2860Sstevel@tonic-gate 		mutex_destroy(&lop->lo_lock);
2870Sstevel@tonic-gate 		kmem_free(lop, sizeof (*lop));
2880Sstevel@tonic-gate 	} else {
2890Sstevel@tonic-gate 		mutex_exit(&lop->lo_lock);
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate /*
2940Sstevel@tonic-gate  * This increments the open owner ref count if found.
2950Sstevel@tonic-gate  * The argument 'just_created' determines whether we are looking for open
2960Sstevel@tonic-gate  * owners with the 'oo_just_created' flag set or not.
2970Sstevel@tonic-gate  */
2980Sstevel@tonic-gate nfs4_open_owner_t *
find_open_owner_nolock(cred_t * cr,int just_created,mntinfo4_t * mi)2990Sstevel@tonic-gate find_open_owner_nolock(cred_t *cr, int just_created, mntinfo4_t *mi)
3000Sstevel@tonic-gate {
3010Sstevel@tonic-gate 	nfs4_open_owner_t	*oop = NULL, *next_oop;
3020Sstevel@tonic-gate 	nfs4_oo_hash_bucket_t	*bucketp;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
3050Sstevel@tonic-gate 	    "find_open_owner: cred %p, just_created %d",
3060Sstevel@tonic-gate 	    (void*)cr, just_created));
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	ASSERT(mi != NULL);
3090Sstevel@tonic-gate 	ASSERT(mutex_owned(&mi->mi_lock));
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	bucketp = lock_bucket(cr, mi);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 	/* got hash bucket, search through open owners */
3140Sstevel@tonic-gate 	for (oop = list_head(&bucketp->b_oo_hash_list); oop != NULL; ) {
3150Sstevel@tonic-gate 		mutex_enter(&oop->oo_lock);
3160Sstevel@tonic-gate 		if (!crcmp(oop->oo_cred, cr) &&
3170Sstevel@tonic-gate 		    (oop->oo_just_created == just_created ||
3180Sstevel@tonic-gate 		    just_created == NFS4_JUST_CREATED)) {
3190Sstevel@tonic-gate 			/* match */
3200Sstevel@tonic-gate 			if (oop->oo_valid == 0) {
3210Sstevel@tonic-gate 				/* reactivate the open owner */
3220Sstevel@tonic-gate 				oop->oo_valid = 1;
3230Sstevel@tonic-gate 				ASSERT(oop->oo_ref_count == 0);
3240Sstevel@tonic-gate 			}
3250Sstevel@tonic-gate 			oop->oo_ref_count++;
3260Sstevel@tonic-gate 			mutex_exit(&oop->oo_lock);
3270Sstevel@tonic-gate 			unlock_bucket(bucketp);
3280Sstevel@tonic-gate 			return (oop);
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 		next_oop = list_next(&bucketp->b_oo_hash_list, oop);
3310Sstevel@tonic-gate 		if (oop->oo_valid == 0) {
3320Sstevel@tonic-gate 			list_remove(&bucketp->b_oo_hash_list, oop);
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 			/*
3350Sstevel@tonic-gate 			 * Now we go ahead and put this open owner
3360Sstevel@tonic-gate 			 * on the freed list.  This is our lazy method.
3370Sstevel@tonic-gate 			 */
3380Sstevel@tonic-gate 			nfs4_free_open_owner(oop, mi);
3390Sstevel@tonic-gate 		}
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		mutex_exit(&oop->oo_lock);
3420Sstevel@tonic-gate 		oop = next_oop;
3430Sstevel@tonic-gate 	}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	/* search through recently freed open owners */
3460Sstevel@tonic-gate 	oop = find_freed_open_owner(cr, bucketp, mi);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	unlock_bucket(bucketp);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	return (oop);
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate nfs4_open_owner_t *
find_open_owner(cred_t * cr,int just_created,mntinfo4_t * mi)3540Sstevel@tonic-gate find_open_owner(cred_t *cr, int just_created, mntinfo4_t *mi)
3550Sstevel@tonic-gate {
3560Sstevel@tonic-gate 	nfs4_open_owner_t *oop;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	mutex_enter(&mi->mi_lock);
3590Sstevel@tonic-gate 	oop = find_open_owner_nolock(cr, just_created, mi);
3600Sstevel@tonic-gate 	mutex_exit(&mi->mi_lock);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	return (oop);
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate  * This increments osp's ref count if found.
3670Sstevel@tonic-gate  * Returns with 'os_sync_lock' held.
3680Sstevel@tonic-gate  */
3690Sstevel@tonic-gate nfs4_open_stream_t *
find_open_stream(nfs4_open_owner_t * oop,rnode4_t * rp)3700Sstevel@tonic-gate find_open_stream(nfs4_open_owner_t *oop, rnode4_t *rp)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	nfs4_open_stream_t	*osp;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
3757902SNagakiran.Rajashekar@Sun.COM 	    "find_open_stream"));
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	mutex_enter(&rp->r_os_lock);
3780Sstevel@tonic-gate 	/* Now, no one can add or delete to rp's open streams list */
3790Sstevel@tonic-gate 	for (osp = list_head(&rp->r_open_streams); osp != NULL;
3800Sstevel@tonic-gate 	    osp = list_next(&rp->r_open_streams, osp)) {
3810Sstevel@tonic-gate 		mutex_enter(&osp->os_sync_lock);
3820Sstevel@tonic-gate 		if (osp->os_open_owner == oop && osp->os_valid != 0) {
3830Sstevel@tonic-gate 			/* match */
3840Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_client_state_debug,
3857902SNagakiran.Rajashekar@Sun.COM 			    (CE_NOTE, "find_open_stream "
3867902SNagakiran.Rajashekar@Sun.COM 			    "got a match"));
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 			osp->os_ref_count++;
3890Sstevel@tonic-gate 			mutex_exit(&rp->r_os_lock);
3900Sstevel@tonic-gate 			return (osp);
3910Sstevel@tonic-gate 		}
3920Sstevel@tonic-gate 		mutex_exit(&osp->os_sync_lock);
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	mutex_exit(&rp->r_os_lock);
3960Sstevel@tonic-gate 	return (NULL);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate /*
4000Sstevel@tonic-gate  * Find the lock owner for the given file and process ID.  If "which" is
4010Sstevel@tonic-gate  * LOWN_VALID_STATEID, require that the lock owner contain a valid stateid
4020Sstevel@tonic-gate  * from the server.
4030Sstevel@tonic-gate  *
4040Sstevel@tonic-gate  * This increments the lock owner's ref count if found.  Returns NULL if
4050Sstevel@tonic-gate  * there was no match.
4060Sstevel@tonic-gate  */
4070Sstevel@tonic-gate nfs4_lock_owner_t *
find_lock_owner(rnode4_t * rp,pid_t pid,lown_which_t which)4080Sstevel@tonic-gate find_lock_owner(rnode4_t *rp, pid_t pid, lown_which_t which)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate 	nfs4_lock_owner_t	*lop, *next_lop;
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
4137902SNagakiran.Rajashekar@Sun.COM 	    "find_lock_owner: pid %x, which %d", pid, which));
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	ASSERT(which == LOWN_ANY || which == LOWN_VALID_STATEID);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	/* search by pid */
4180Sstevel@tonic-gate 	mutex_enter(&rp->r_statev4_lock);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	lop = rp->r_lo_head.lo_next_rnode;
4210Sstevel@tonic-gate 	while (lop != &rp->r_lo_head) {
4220Sstevel@tonic-gate 		mutex_enter(&lop->lo_lock);
4230Sstevel@tonic-gate 		if (lop->lo_pid == pid && lop->lo_valid != 0 &&
4240Sstevel@tonic-gate 		    !(lop->lo_flags & NFS4_BAD_SEQID_LOCK)) {
4250Sstevel@tonic-gate 			if (which == LOWN_ANY ||
4260Sstevel@tonic-gate 			    lop->lo_just_created != NFS4_JUST_CREATED) {
4270Sstevel@tonic-gate 				/* Found a matching lock owner */
4280Sstevel@tonic-gate 				NFS4_DEBUG(nfs4_client_state_debug,
4297902SNagakiran.Rajashekar@Sun.COM 				    (CE_NOTE, "find_lock_owner: "
4307902SNagakiran.Rajashekar@Sun.COM 				    "got a match"));
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 				lop->lo_ref_count++;
4330Sstevel@tonic-gate 				mutex_exit(&lop->lo_lock);
4340Sstevel@tonic-gate 				mutex_exit(&rp->r_statev4_lock);
4350Sstevel@tonic-gate 				return (lop);
4360Sstevel@tonic-gate 			}
4370Sstevel@tonic-gate 		}
4380Sstevel@tonic-gate 		next_lop = lop->lo_next_rnode;
4390Sstevel@tonic-gate 		mutex_exit(&lop->lo_lock);
4400Sstevel@tonic-gate 		lop = next_lop;
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	mutex_exit(&rp->r_statev4_lock);
4440Sstevel@tonic-gate 	return (NULL);
4450Sstevel@tonic-gate }
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate /*
4480Sstevel@tonic-gate  * This returns the delegation stateid as 'sid'. Returns 1 if a successful
4490Sstevel@tonic-gate  * delegation stateid was found, otherwise returns 0.
4500Sstevel@tonic-gate  */
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate static int
nfs4_get_deleg_stateid(rnode4_t * rp,nfs_opnum4 op,stateid4 * sid)4530Sstevel@tonic-gate nfs4_get_deleg_stateid(rnode4_t *rp, nfs_opnum4 op, stateid4 *sid)
4540Sstevel@tonic-gate {
4550Sstevel@tonic-gate 	ASSERT(!mutex_owned(&rp->r_statev4_lock));
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	mutex_enter(&rp->r_statev4_lock);
4580Sstevel@tonic-gate 	if (((rp->r_deleg_type == OPEN_DELEGATE_WRITE && op == OP_WRITE) ||
4590Sstevel@tonic-gate 	    (rp->r_deleg_type != OPEN_DELEGATE_NONE && op != OP_WRITE)) &&
4600Sstevel@tonic-gate 	    !rp->r_deleg_return_pending) {
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		*sid = rp->r_deleg_stateid;
4630Sstevel@tonic-gate 		mutex_exit(&rp->r_statev4_lock);
4640Sstevel@tonic-gate 		return (1);
4650Sstevel@tonic-gate 	}
4660Sstevel@tonic-gate 	mutex_exit(&rp->r_statev4_lock);
4670Sstevel@tonic-gate 	return (0);
4680Sstevel@tonic-gate }
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate /*
4710Sstevel@tonic-gate  * This returns the lock stateid as 'sid'. Returns 1 if a successful lock
4720Sstevel@tonic-gate  * stateid was found, otherwise returns 0.
4730Sstevel@tonic-gate  */
4740Sstevel@tonic-gate static int
nfs4_get_lock_stateid(rnode4_t * rp,pid_t pid,stateid4 * sid)4750Sstevel@tonic-gate nfs4_get_lock_stateid(rnode4_t *rp, pid_t pid, stateid4 *sid)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	nfs4_lock_owner_t *lop;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	lop = find_lock_owner(rp, pid, LOWN_VALID_STATEID);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	if (lop) {
4820Sstevel@tonic-gate 		/*
4830Sstevel@tonic-gate 		 * Found a matching lock owner, so use a lock
4840Sstevel@tonic-gate 		 * stateid rather than an open stateid.
4850Sstevel@tonic-gate 		 */
4860Sstevel@tonic-gate 		mutex_enter(&lop->lo_lock);
4870Sstevel@tonic-gate 		*sid = lop->lock_stateid;
4880Sstevel@tonic-gate 		mutex_exit(&lop->lo_lock);
4890Sstevel@tonic-gate 		lock_owner_rele(lop);
4900Sstevel@tonic-gate 		return (1);
4910Sstevel@tonic-gate 	}
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
4940Sstevel@tonic-gate 	    "nfs4_get_lock_stateid: no lop"));
4950Sstevel@tonic-gate 	return (0);
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate  * This returns the open stateid as 'sid'. Returns 1 if a successful open
5000Sstevel@tonic-gate  * stateid was found, otherwise returns 0.
5010Sstevel@tonic-gate  *
5020Sstevel@tonic-gate  * Once the stateid is returned to the caller, it is no longer protected;
5030Sstevel@tonic-gate  * so the caller must be prepared to handle OLD/BAD_STATEID where
5040Sstevel@tonic-gate  * appropiate.
5050Sstevel@tonic-gate  */
5060Sstevel@tonic-gate static int
nfs4_get_open_stateid(rnode4_t * rp,cred_t * cr,mntinfo4_t * mi,stateid4 * sid)5070Sstevel@tonic-gate nfs4_get_open_stateid(rnode4_t *rp, cred_t *cr, mntinfo4_t *mi, stateid4 *sid)
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate 	nfs4_open_owner_t *oop;
5100Sstevel@tonic-gate 	nfs4_open_stream_t *osp;
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	ASSERT(mi != NULL);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	oop = find_open_owner(cr, NFS4_PERM_CREATED, mi);
5150Sstevel@tonic-gate 	if (!oop) {
5160Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
5170Sstevel@tonic-gate 		    "nfs4_get_open_stateid: no oop"));
5180Sstevel@tonic-gate 		return (0);
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	osp = find_open_stream(oop, rp);
5220Sstevel@tonic-gate 	open_owner_rele(oop);
5230Sstevel@tonic-gate 	if (!osp) {
5240Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
5250Sstevel@tonic-gate 		    "nfs4_get_open_stateid: no osp"));
5260Sstevel@tonic-gate 		return (0);
5270Sstevel@tonic-gate 	}
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if (osp->os_failed_reopen) {
5300Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
5310Sstevel@tonic-gate 		    "nfs4_get_open_stateid: osp %p failed reopen",
5320Sstevel@tonic-gate 		    (void *)osp));
5330Sstevel@tonic-gate 		mutex_exit(&osp->os_sync_lock);
5340Sstevel@tonic-gate 		open_stream_rele(osp, rp);
5350Sstevel@tonic-gate 		return (0);
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 	*sid = osp->open_stateid;
5380Sstevel@tonic-gate 	mutex_exit(&osp->os_sync_lock);
5390Sstevel@tonic-gate 	open_stream_rele(osp, rp);
5400Sstevel@tonic-gate 	return (1);
5410Sstevel@tonic-gate }
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate /*
5440Sstevel@tonic-gate  * Returns the delegation stateid if this 'op' is OP_WRITE and the
5450Sstevel@tonic-gate  * delegation we hold is a write delegation, OR this 'op' is not
5460Sstevel@tonic-gate  * OP_WRITE and we have a delegation held (read or write), otherwise
5470Sstevel@tonic-gate  * returns the lock stateid if there is a lock owner, otherwise
5480Sstevel@tonic-gate  * returns the open stateid if there is a open stream, otherwise
5490Sstevel@tonic-gate  * returns special stateid <seqid = 0, other = 0>.
5500Sstevel@tonic-gate  *
5510Sstevel@tonic-gate  * Used for WRITE operations.
5520Sstevel@tonic-gate  */
5530Sstevel@tonic-gate stateid4
nfs4_get_w_stateid(cred_t * cr,rnode4_t * rp,pid_t pid,mntinfo4_t * mi,nfs_opnum4 op,nfs4_stateid_types_t * sid_tp)5540Sstevel@tonic-gate nfs4_get_w_stateid(cred_t *cr, rnode4_t *rp, pid_t pid, mntinfo4_t *mi,
5550Sstevel@tonic-gate 	nfs_opnum4 op, nfs4_stateid_types_t *sid_tp)
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate 	stateid4 sid;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	if (nfs4_get_deleg_stateid(rp, op, &sid)) {
5600Sstevel@tonic-gate 		if (!stateid4_cmp(&sid, &sid_tp->d_sid)) {
5610Sstevel@tonic-gate 			sid_tp->cur_sid_type = DEL_SID;
5620Sstevel@tonic-gate 			return (sid);
5630Sstevel@tonic-gate 		}
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 	if (nfs4_get_lock_stateid(rp, pid, &sid)) {
5660Sstevel@tonic-gate 		if (!stateid4_cmp(&sid, &sid_tp->l_sid)) {
5670Sstevel@tonic-gate 			sid_tp->cur_sid_type = LOCK_SID;
5680Sstevel@tonic-gate 			return (sid);
5690Sstevel@tonic-gate 		}
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 	if (nfs4_get_open_stateid(rp, cr, mi, &sid)) {
5720Sstevel@tonic-gate 		if (!stateid4_cmp(&sid, &sid_tp->o_sid)) {
5730Sstevel@tonic-gate 			sid_tp->cur_sid_type = OPEN_SID;
5740Sstevel@tonic-gate 			return (sid);
5750Sstevel@tonic-gate 		}
5760Sstevel@tonic-gate 	}
5770Sstevel@tonic-gate 	bzero(&sid, sizeof (stateid4));
5780Sstevel@tonic-gate 	sid_tp->cur_sid_type = SPEC_SID;
5790Sstevel@tonic-gate 	return (sid);
5800Sstevel@tonic-gate }
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate /*
5830Sstevel@tonic-gate  * Returns the delegation stateid if this 'op' is OP_WRITE and the
5840Sstevel@tonic-gate  * delegation we hold is a write delegation, OR this 'op' is not
5850Sstevel@tonic-gate  * OP_WRITE and we have a delegation held (read or write), otherwise
5860Sstevel@tonic-gate  * returns the lock stateid if there is a lock owner, otherwise
5870Sstevel@tonic-gate  * returns the open stateid if there is a open stream, otherwise
5880Sstevel@tonic-gate  * returns special stateid <seqid = 0, other = 0>.
5890Sstevel@tonic-gate  *
5900Sstevel@tonic-gate  * This also updates which stateid we are using in 'sid_tp', skips
5910Sstevel@tonic-gate  * previously attempted stateids, and skips checking higher priority
5920Sstevel@tonic-gate  * stateids than the current level as dictated by 'sid_tp->cur_sid_type'
5930Sstevel@tonic-gate  * for async reads.
5940Sstevel@tonic-gate  *
5950Sstevel@tonic-gate  * Used for READ and SETATTR operations.
5960Sstevel@tonic-gate  */
5970Sstevel@tonic-gate stateid4
nfs4_get_stateid(cred_t * cr,rnode4_t * rp,pid_t pid,mntinfo4_t * mi,nfs_opnum4 op,nfs4_stateid_types_t * sid_tp,bool_t async_read)5980Sstevel@tonic-gate nfs4_get_stateid(cred_t *cr, rnode4_t *rp, pid_t pid, mntinfo4_t *mi,
5990Sstevel@tonic-gate 	nfs_opnum4 op, nfs4_stateid_types_t *sid_tp, bool_t async_read)
6000Sstevel@tonic-gate {
6010Sstevel@tonic-gate 	stateid4 sid;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	/*
6040Sstevel@tonic-gate 	 * For asynchronous READs, do not attempt to retry from the start of
6050Sstevel@tonic-gate 	 * the stateid priority list, just continue from where you last left
6060Sstevel@tonic-gate 	 * off.
6070Sstevel@tonic-gate 	 */
6080Sstevel@tonic-gate 	if (async_read) {
6090Sstevel@tonic-gate 		switch (sid_tp->cur_sid_type) {
6100Sstevel@tonic-gate 		case NO_SID:
6110Sstevel@tonic-gate 			break;
6120Sstevel@tonic-gate 		case DEL_SID:
6130Sstevel@tonic-gate 			goto lock_stateid;
6140Sstevel@tonic-gate 		case LOCK_SID:
6150Sstevel@tonic-gate 			goto open_stateid;
6160Sstevel@tonic-gate 		case OPEN_SID:
6170Sstevel@tonic-gate 			goto special_stateid;
6180Sstevel@tonic-gate 		case SPEC_SID:
6190Sstevel@tonic-gate 		default:
6200Sstevel@tonic-gate 			cmn_err(CE_PANIC, "nfs4_get_stateid: illegal current "
6210Sstevel@tonic-gate 			    "stateid type %d", sid_tp->cur_sid_type);
6220Sstevel@tonic-gate 		}
6230Sstevel@tonic-gate 	}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	if (nfs4_get_deleg_stateid(rp, op, &sid)) {
6260Sstevel@tonic-gate 		if (!stateid4_cmp(&sid, &sid_tp->d_sid)) {
6270Sstevel@tonic-gate 			sid_tp->cur_sid_type = DEL_SID;
6280Sstevel@tonic-gate 			return (sid);
6290Sstevel@tonic-gate 		}
6300Sstevel@tonic-gate 	}
6310Sstevel@tonic-gate lock_stateid:
6320Sstevel@tonic-gate 	if (nfs4_get_lock_stateid(rp, pid, &sid)) {
6330Sstevel@tonic-gate 		if (!stateid4_cmp(&sid, &sid_tp->l_sid)) {
6340Sstevel@tonic-gate 			sid_tp->cur_sid_type = LOCK_SID;
6350Sstevel@tonic-gate 			return (sid);
6360Sstevel@tonic-gate 		}
6370Sstevel@tonic-gate 	}
6380Sstevel@tonic-gate open_stateid:
6390Sstevel@tonic-gate 	if (nfs4_get_open_stateid(rp, cr, mi, &sid)) {
6400Sstevel@tonic-gate 		if (!stateid4_cmp(&sid, &sid_tp->o_sid)) {
6410Sstevel@tonic-gate 			sid_tp->cur_sid_type = OPEN_SID;
6420Sstevel@tonic-gate 			return (sid);
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate special_stateid:
6460Sstevel@tonic-gate 	bzero(&sid, sizeof (stateid4));
6470Sstevel@tonic-gate 	sid_tp->cur_sid_type = SPEC_SID;
6480Sstevel@tonic-gate 	return	(sid);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate void
nfs4_set_lock_stateid(nfs4_lock_owner_t * lop,stateid4 stateid)6520Sstevel@tonic-gate nfs4_set_lock_stateid(nfs4_lock_owner_t *lop, stateid4 stateid)
6530Sstevel@tonic-gate {
6540Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
6557902SNagakiran.Rajashekar@Sun.COM 	    "nfs4_set_lock_stateid"));
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	ASSERT(lop);
6580Sstevel@tonic-gate 	ASSERT(lop->lo_flags & NFS4_LOCK_SEQID_INUSE);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	mutex_enter(&lop->lo_lock);
6610Sstevel@tonic-gate 	lop->lock_stateid = stateid;
6620Sstevel@tonic-gate 	mutex_exit(&lop->lo_lock);
6630Sstevel@tonic-gate }
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate /*
6660Sstevel@tonic-gate  * Sequence number used when a new open owner is needed.
6670Sstevel@tonic-gate  * This is used so as to not confuse the server.  Since a open owner
6680Sstevel@tonic-gate  * is based off of cred, a cred could be re-used quickly, and the server
6690Sstevel@tonic-gate  * may not release all state for a cred.
6700Sstevel@tonic-gate  */
6710Sstevel@tonic-gate static uint64_t open_owner_seq_num = 0;
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate uint64_t
nfs4_get_new_oo_name(void)6740Sstevel@tonic-gate nfs4_get_new_oo_name(void)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate 	return (atomic_add_64_nv(&open_owner_seq_num, 1));
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate /*
6800Sstevel@tonic-gate  * Create a new open owner and add it to the open owner hash table.
6810Sstevel@tonic-gate  */
6820Sstevel@tonic-gate nfs4_open_owner_t *
create_open_owner(cred_t * cr,mntinfo4_t * mi)6830Sstevel@tonic-gate create_open_owner(cred_t *cr, mntinfo4_t *mi)
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	nfs4_open_owner_t	*oop;
6860Sstevel@tonic-gate 	nfs4_oo_hash_bucket_t	*bucketp;
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	oop = kmem_alloc(sizeof (nfs4_open_owner_t), KM_SLEEP);
6890Sstevel@tonic-gate 	/*
6900Sstevel@tonic-gate 	 * Make sure the cred doesn't go away when we put this open owner
6910Sstevel@tonic-gate 	 * on the free list, as well as make crcmp() a valid check.
6920Sstevel@tonic-gate 	 */
6930Sstevel@tonic-gate 	crhold(cr);
6940Sstevel@tonic-gate 	oop->oo_cred = cr;
6950Sstevel@tonic-gate 	mutex_init(&oop->oo_lock, NULL, MUTEX_DEFAULT, NULL);
6960Sstevel@tonic-gate 	oop->oo_ref_count = 1;
6970Sstevel@tonic-gate 	oop->oo_valid = 1;
6980Sstevel@tonic-gate 	oop->oo_just_created = NFS4_JUST_CREATED;
6990Sstevel@tonic-gate 	oop->oo_seqid = 0;
7000Sstevel@tonic-gate 	oop->oo_seqid_inuse = 0;
7010Sstevel@tonic-gate 	oop->oo_last_good_seqid = 0;
7020Sstevel@tonic-gate 	oop->oo_last_good_op = TAG_NONE;
7030Sstevel@tonic-gate 	oop->oo_cred_otw = NULL;
7040Sstevel@tonic-gate 	cv_init(&oop->oo_cv_seqid_sync, NULL, CV_DEFAULT, NULL);
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	/*
7070Sstevel@tonic-gate 	 * A Solaris open_owner is <oo_seq_num>
7080Sstevel@tonic-gate 	 */
7090Sstevel@tonic-gate 	oop->oo_name = nfs4_get_new_oo_name();
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/* now add the struct into the cred hash table */
7120Sstevel@tonic-gate 	ASSERT(mutex_owned(&mi->mi_lock));
7130Sstevel@tonic-gate 	bucketp = lock_bucket(cr, mi);
7140Sstevel@tonic-gate 	list_insert_head(&bucketp->b_oo_hash_list, oop);
7150Sstevel@tonic-gate 	unlock_bucket(bucketp);
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	return (oop);
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate /*
7210Sstevel@tonic-gate  * Create a new open stream and it to the rnode's list.
7220Sstevel@tonic-gate  * Increments the ref count on oop.
7230Sstevel@tonic-gate  * Returns with 'os_sync_lock' held.
7240Sstevel@tonic-gate  */
7250Sstevel@tonic-gate nfs4_open_stream_t *
create_open_stream(nfs4_open_owner_t * oop,rnode4_t * rp)7260Sstevel@tonic-gate create_open_stream(nfs4_open_owner_t *oop, rnode4_t *rp)
7270Sstevel@tonic-gate {
7280Sstevel@tonic-gate 	nfs4_open_stream_t	*osp;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate #ifdef DEBUG
7310Sstevel@tonic-gate 	mutex_enter(&oop->oo_lock);
7320Sstevel@tonic-gate 	ASSERT(oop->oo_seqid_inuse);
7330Sstevel@tonic-gate 	mutex_exit(&oop->oo_lock);
7340Sstevel@tonic-gate #endif
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	osp = kmem_alloc(sizeof (nfs4_open_stream_t), KM_SLEEP);
7370Sstevel@tonic-gate 	osp->os_open_ref_count = 1;
7380Sstevel@tonic-gate 	osp->os_mapcnt = 0;
7390Sstevel@tonic-gate 	osp->os_ref_count = 2;
7400Sstevel@tonic-gate 	osp->os_valid = 1;
7410Sstevel@tonic-gate 	osp->os_open_owner = oop;
7420Sstevel@tonic-gate 	osp->os_orig_oo_name = oop->oo_name;
7430Sstevel@tonic-gate 	bzero(&osp->open_stateid, sizeof (stateid4));
7440Sstevel@tonic-gate 	osp->os_share_acc_read = 0;
7450Sstevel@tonic-gate 	osp->os_share_acc_write = 0;
7460Sstevel@tonic-gate 	osp->os_mmap_read = 0;
7470Sstevel@tonic-gate 	osp->os_mmap_write = 0;
7480Sstevel@tonic-gate 	osp->os_share_deny_none = 0;
7490Sstevel@tonic-gate 	osp->os_share_deny_read = 0;
7500Sstevel@tonic-gate 	osp->os_share_deny_write = 0;
7510Sstevel@tonic-gate 	osp->os_delegation = 0;
7520Sstevel@tonic-gate 	osp->os_dc_openacc = 0;
7530Sstevel@tonic-gate 	osp->os_final_close = 0;
7540Sstevel@tonic-gate 	osp->os_pending_close = 0;
7550Sstevel@tonic-gate 	osp->os_failed_reopen = 0;
7560Sstevel@tonic-gate 	osp->os_force_close = 0;
7570Sstevel@tonic-gate 	mutex_init(&osp->os_sync_lock, NULL, MUTEX_DEFAULT, NULL);
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	/* open owner gets a reference */
7600Sstevel@tonic-gate 	open_owner_hold(oop);
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	/* now add the open stream to rp */
7630Sstevel@tonic-gate 	mutex_enter(&rp->r_os_lock);
7640Sstevel@tonic-gate 	mutex_enter(&osp->os_sync_lock);
7650Sstevel@tonic-gate 	list_insert_head(&rp->r_open_streams, osp);
7660Sstevel@tonic-gate 	mutex_exit(&rp->r_os_lock);
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	return (osp);
7690Sstevel@tonic-gate }
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate /*
7720Sstevel@tonic-gate  * Returns an open stream with 'os_sync_lock' held.
7730Sstevel@tonic-gate  * If the open stream is found (rather than created), its
7740Sstevel@tonic-gate  * 'os_open_ref_count' is bumped.
7750Sstevel@tonic-gate  *
7760Sstevel@tonic-gate  * There is no race with two threads entering this function
7770Sstevel@tonic-gate  * and creating two open streams for the same <oop, rp> pair.
7780Sstevel@tonic-gate  * This is because the open seqid sync must be acquired, thus
7790Sstevel@tonic-gate  * only allowing one thread in at a time.
7800Sstevel@tonic-gate  */
7810Sstevel@tonic-gate nfs4_open_stream_t *
find_or_create_open_stream(nfs4_open_owner_t * oop,rnode4_t * rp,int * created_osp)7820Sstevel@tonic-gate find_or_create_open_stream(nfs4_open_owner_t *oop, rnode4_t *rp,
7830Sstevel@tonic-gate 	int *created_osp)
7840Sstevel@tonic-gate {
7850Sstevel@tonic-gate 	nfs4_open_stream_t *osp;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate #ifdef DEBUG
7880Sstevel@tonic-gate 	mutex_enter(&oop->oo_lock);
7890Sstevel@tonic-gate 	ASSERT(oop->oo_seqid_inuse);
7900Sstevel@tonic-gate 	mutex_exit(&oop->oo_lock);
7910Sstevel@tonic-gate #endif
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	osp = find_open_stream(oop, rp);
7940Sstevel@tonic-gate 	if (!osp) {
7950Sstevel@tonic-gate 		osp = create_open_stream(oop, rp);
7960Sstevel@tonic-gate 		if (osp)
7970Sstevel@tonic-gate 			*created_osp = 1;
7980Sstevel@tonic-gate 	} else {
7990Sstevel@tonic-gate 		*created_osp = 0;
8000Sstevel@tonic-gate 		osp->os_open_ref_count++;
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	return (osp);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate static uint64_t lock_owner_seq_num = 0;
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate /*
8090Sstevel@tonic-gate  * Create a new lock owner and add it to the rnode's list.
8100Sstevel@tonic-gate  * Assumes the rnode's r_statev4_lock is held.
8110Sstevel@tonic-gate  * The created lock owner has a reference count of 2: one for the list and
8120Sstevel@tonic-gate  * one for the caller to use.  Returns the lock owner locked down.
8130Sstevel@tonic-gate  */
8140Sstevel@tonic-gate nfs4_lock_owner_t *
create_lock_owner(rnode4_t * rp,pid_t pid)8150Sstevel@tonic-gate create_lock_owner(rnode4_t *rp, pid_t pid)
8160Sstevel@tonic-gate {
8170Sstevel@tonic-gate 	nfs4_lock_owner_t	*lop;
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
8207902SNagakiran.Rajashekar@Sun.COM 	    "create_lock_owner: pid %x", pid));
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 	ASSERT(mutex_owned(&rp->r_statev4_lock));
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	lop = kmem_alloc(sizeof (nfs4_lock_owner_t), KM_SLEEP);
8250Sstevel@tonic-gate 	lop->lo_ref_count = 2;
8260Sstevel@tonic-gate 	lop->lo_valid = 1;
8270Sstevel@tonic-gate 	bzero(&lop->lock_stateid, sizeof (stateid4));
8280Sstevel@tonic-gate 	lop->lo_pid = pid;
8290Sstevel@tonic-gate 	lop->lock_seqid = 0;
8300Sstevel@tonic-gate 	lop->lo_pending_rqsts = 0;
8310Sstevel@tonic-gate 	lop->lo_just_created = NFS4_JUST_CREATED;
8320Sstevel@tonic-gate 	lop->lo_flags = 0;
8330Sstevel@tonic-gate 	lop->lo_seqid_holder = NULL;
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 	/*
8360Sstevel@tonic-gate 	 * A Solaris lock_owner is <seq_num><pid>
8370Sstevel@tonic-gate 	 */
8380Sstevel@tonic-gate 	lop->lock_owner_name.ln_seq_num =
8397902SNagakiran.Rajashekar@Sun.COM 	    atomic_add_64_nv(&lock_owner_seq_num, 1);
8400Sstevel@tonic-gate 	lop->lock_owner_name.ln_pid = pid;
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	cv_init(&lop->lo_cv_seqid_sync, NULL, CV_DEFAULT, NULL);
8430Sstevel@tonic-gate 	mutex_init(&lop->lo_lock, NULL, MUTEX_DEFAULT, NULL);
8440Sstevel@tonic-gate 
8450Sstevel@tonic-gate 	mutex_enter(&lop->lo_lock);
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	/* now add the lock owner to rp */
8480Sstevel@tonic-gate 	lop->lo_prev_rnode = &rp->r_lo_head;
8490Sstevel@tonic-gate 	lop->lo_next_rnode = rp->r_lo_head.lo_next_rnode;
8500Sstevel@tonic-gate 	rp->r_lo_head.lo_next_rnode->lo_prev_rnode = lop;
8510Sstevel@tonic-gate 	rp->r_lo_head.lo_next_rnode = lop;
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	return (lop);
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate /*
8580Sstevel@tonic-gate  * This sets the lock seqid of a lock owner.
8590Sstevel@tonic-gate  */
8600Sstevel@tonic-gate void
nfs4_set_lock_seqid(seqid4 seqid,nfs4_lock_owner_t * lop)8610Sstevel@tonic-gate nfs4_set_lock_seqid(seqid4 seqid, nfs4_lock_owner_t *lop)
8620Sstevel@tonic-gate {
8630Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
8647902SNagakiran.Rajashekar@Sun.COM 	    "nfs4_set_lock_seqid"));
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	ASSERT(lop != NULL);
8670Sstevel@tonic-gate 	ASSERT(lop->lo_flags & NFS4_LOCK_SEQID_INUSE);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	lop->lock_seqid = seqid;
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate static void
nfs4_set_new_lock_owner_args(lock_owner4 * owner,pid_t pid)8730Sstevel@tonic-gate nfs4_set_new_lock_owner_args(lock_owner4 *owner, pid_t pid)
8740Sstevel@tonic-gate {
8750Sstevel@tonic-gate 	nfs4_lo_name_t *cast_namep;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
8787902SNagakiran.Rajashekar@Sun.COM 	    "nfs4_set_new_lock_owner_args"));
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	owner->owner_len = sizeof (*cast_namep);
8810Sstevel@tonic-gate 	owner->owner_val = kmem_alloc(owner->owner_len, KM_SLEEP);
8820Sstevel@tonic-gate 	/*
8830Sstevel@tonic-gate 	 * A Solaris lock_owner is <seq_num><pid>
8840Sstevel@tonic-gate 	 */
8850Sstevel@tonic-gate 	cast_namep = (nfs4_lo_name_t *)owner->owner_val;
8860Sstevel@tonic-gate 	cast_namep->ln_seq_num = atomic_add_64_nv(&lock_owner_seq_num, 1);
8870Sstevel@tonic-gate 	cast_namep->ln_pid = pid;
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate /*
8910Sstevel@tonic-gate  * Fill in the lock owner args.
8920Sstevel@tonic-gate  */
8930Sstevel@tonic-gate void
nfs4_setlockowner_args(lock_owner4 * owner,rnode4_t * rp,pid_t pid)8940Sstevel@tonic-gate nfs4_setlockowner_args(lock_owner4 *owner, rnode4_t *rp, pid_t pid)
8950Sstevel@tonic-gate {
8960Sstevel@tonic-gate 	nfs4_lock_owner_t *lop;
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
8997902SNagakiran.Rajashekar@Sun.COM 	    "nfs4_setlockowner_args"));
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	/* This increments lop's ref count */
9020Sstevel@tonic-gate 	lop = find_lock_owner(rp, pid, LOWN_VALID_STATEID);
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	if (!lop)
9050Sstevel@tonic-gate 		goto make_up_args;
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	mutex_enter(&lop->lo_lock);
9080Sstevel@tonic-gate 	owner->owner_len = sizeof (lop->lock_owner_name);
9090Sstevel@tonic-gate 	owner->owner_val = kmem_alloc(owner->owner_len, KM_SLEEP);
9100Sstevel@tonic-gate 	bcopy(&lop->lock_owner_name, owner->owner_val,
9117902SNagakiran.Rajashekar@Sun.COM 	    owner->owner_len);
9120Sstevel@tonic-gate 	mutex_exit(&lop->lo_lock);
9130Sstevel@tonic-gate 	lock_owner_rele(lop);
9140Sstevel@tonic-gate 	return;
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate make_up_args:
9170Sstevel@tonic-gate 	nfs4_set_new_lock_owner_args(owner, pid);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate /*
9210Sstevel@tonic-gate  * This ends our use of the open owner's open seqid by setting
9220Sstevel@tonic-gate  * the appropiate flags and issuing a cv_signal to wake up another
9230Sstevel@tonic-gate  * thread waiting to use the open seqid.
9240Sstevel@tonic-gate  */
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate void
nfs4_end_open_seqid_sync(nfs4_open_owner_t * oop)9270Sstevel@tonic-gate nfs4_end_open_seqid_sync(nfs4_open_owner_t *oop)
9280Sstevel@tonic-gate {
9290Sstevel@tonic-gate 	mutex_enter(&oop->oo_lock);
9300Sstevel@tonic-gate 	ASSERT(oop->oo_seqid_inuse);
9310Sstevel@tonic-gate 	oop->oo_seqid_inuse = 0;
9320Sstevel@tonic-gate 	cv_broadcast(&oop->oo_cv_seqid_sync);
9330Sstevel@tonic-gate 	mutex_exit(&oop->oo_lock);
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate /*
9370Sstevel@tonic-gate  * This starts our use of the open owner's open seqid by setting
9380Sstevel@tonic-gate  * the oo_seqid_inuse to true.  We will wait (forever) with a
9390Sstevel@tonic-gate  * cv_wait() until we are woken up.
9400Sstevel@tonic-gate  *
9410Sstevel@tonic-gate  * Return values:
9420Sstevel@tonic-gate  * 0		no problems
9430Sstevel@tonic-gate  * EAGAIN	caller should retry (like a recovery retry)
9440Sstevel@tonic-gate  */
9450Sstevel@tonic-gate int
nfs4_start_open_seqid_sync(nfs4_open_owner_t * oop,mntinfo4_t * mi)9460Sstevel@tonic-gate nfs4_start_open_seqid_sync(nfs4_open_owner_t *oop, mntinfo4_t *mi)
9470Sstevel@tonic-gate {
9480Sstevel@tonic-gate 	int error = 0;
9490Sstevel@tonic-gate #ifdef DEBUG
9500Sstevel@tonic-gate 	static int ops = 0;		/* fault injection */
9510Sstevel@tonic-gate #endif
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate #ifdef DEBUG
9540Sstevel@tonic-gate 	if (seqid_sync_faults && curthread != mi->mi_recovthread &&
9550Sstevel@tonic-gate 	    ++ops % 5 == 0)
9560Sstevel@tonic-gate 		return (EAGAIN);
9570Sstevel@tonic-gate #endif
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	mutex_enter(&mi->mi_lock);
9600Sstevel@tonic-gate 	if ((mi->mi_flags & MI4_RECOV_ACTIV) &&
9610Sstevel@tonic-gate 	    curthread != mi->mi_recovthread)
9620Sstevel@tonic-gate 		error = EAGAIN;
9630Sstevel@tonic-gate 	mutex_exit(&mi->mi_lock);
9640Sstevel@tonic-gate 	if (error != 0)
9650Sstevel@tonic-gate 		goto done;
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	mutex_enter(&oop->oo_lock);
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	while (oop->oo_seqid_inuse) {
9700Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_seqid_sync, (CE_NOTE,
9717902SNagakiran.Rajashekar@Sun.COM 		    "nfs4_start_open_seqid_sync waiting on cv"));
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate 		cv_wait(&oop->oo_cv_seqid_sync, &oop->oo_lock);
9740Sstevel@tonic-gate 	}
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	oop->oo_seqid_inuse = 1;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	mutex_exit(&oop->oo_lock);
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	mutex_enter(&mi->mi_lock);
9810Sstevel@tonic-gate 	if ((mi->mi_flags & MI4_RECOV_ACTIV) &&
9820Sstevel@tonic-gate 	    curthread != mi->mi_recovthread)
9830Sstevel@tonic-gate 		error = EAGAIN;
9840Sstevel@tonic-gate 	mutex_exit(&mi->mi_lock);
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	if (error == EAGAIN)
9870Sstevel@tonic-gate 		nfs4_end_open_seqid_sync(oop);
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_seqid_sync, (CE_NOTE,
9907902SNagakiran.Rajashekar@Sun.COM 	    "nfs4_start_open_seqid_sync: error=%d", error));
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate done:
9930Sstevel@tonic-gate 	return (error);
9940Sstevel@tonic-gate }
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate #ifdef	DEBUG
9970Sstevel@tonic-gate int bypass_otw[2];
9980Sstevel@tonic-gate #endif
9990Sstevel@tonic-gate 
10000Sstevel@tonic-gate /*
10010Sstevel@tonic-gate  * Checks to see if the OPEN OTW is necessary that is, if it's already
10020Sstevel@tonic-gate  * been opened with the same access and deny bits we are now asking for.
10030Sstevel@tonic-gate  * Note, this assumes that *vpp is a rnode.
10040Sstevel@tonic-gate  */
10050Sstevel@tonic-gate int
nfs4_is_otw_open_necessary(nfs4_open_owner_t * oop,int flag,vnode_t * vp,int just_been_created,int * errorp,int acc,nfs4_recov_state_t * rsp)10060Sstevel@tonic-gate nfs4_is_otw_open_necessary(nfs4_open_owner_t *oop, int flag, vnode_t *vp,
10070Sstevel@tonic-gate 	int just_been_created, int *errorp, int acc, nfs4_recov_state_t *rsp)
10080Sstevel@tonic-gate {
10090Sstevel@tonic-gate 	rnode4_t *rp;
10100Sstevel@tonic-gate 	nfs4_open_stream_t *osp;
10110Sstevel@tonic-gate 	open_delegation_type4 dt;
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	rp = VTOR4(vp);
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	/*
10160Sstevel@tonic-gate 	 * Grab the delegation type.  This function is protected against
10170Sstevel@tonic-gate 	 * the delegation being returned by virtue of start_op (called
10180Sstevel@tonic-gate 	 * by nfs4open_otw) taking the r_deleg_recall_lock in read mode,
10190Sstevel@tonic-gate 	 * delegreturn requires this lock in write mode to proceed.
10200Sstevel@tonic-gate 	 */
10210Sstevel@tonic-gate 	ASSERT(nfs_rw_lock_held(&rp->r_deleg_recall_lock, RW_READER));
10220Sstevel@tonic-gate 	dt = get_dtype(rp);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	/* returns with 'os_sync_lock' held */
10250Sstevel@tonic-gate 	osp = find_open_stream(oop, rp);
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	if (osp) {
10280Sstevel@tonic-gate 		uint32_t	do_otw = 0;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 		if (osp->os_failed_reopen) {
10310Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_open_stream_debug, (CE_NOTE,
10320Sstevel@tonic-gate 			    "nfs4_is_otw_open_necessary: os_failed_reopen "
10330Sstevel@tonic-gate 			    "set on osp %p, cr %p, rp %s", (void *)osp,
10340Sstevel@tonic-gate 			    (void *)osp->os_open_owner->oo_cred,
10350Sstevel@tonic-gate 			    rnode4info(rp)));
10360Sstevel@tonic-gate 			do_otw = 1;
10370Sstevel@tonic-gate 		}
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 		/*
10400Sstevel@tonic-gate 		 * check access/deny bits
10410Sstevel@tonic-gate 		 */
10420Sstevel@tonic-gate 		if (!do_otw && (flag & FREAD))
10430Sstevel@tonic-gate 			if (osp->os_share_acc_read == 0 &&
10440Sstevel@tonic-gate 			    dt == OPEN_DELEGATE_NONE)
10450Sstevel@tonic-gate 				do_otw = 1;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 		if (!do_otw && (flag & FWRITE))
10480Sstevel@tonic-gate 			if (osp->os_share_acc_write == 0 &&
10490Sstevel@tonic-gate 			    dt != OPEN_DELEGATE_WRITE)
10500Sstevel@tonic-gate 				do_otw = 1;
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 		if (!do_otw) {
10530Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
10547902SNagakiran.Rajashekar@Sun.COM 			    "nfs4_is_otw_open_necessary: can skip this "
10557902SNagakiran.Rajashekar@Sun.COM 			    "open OTW"));
10560Sstevel@tonic-gate 			if (!just_been_created) {
10570Sstevel@tonic-gate 				osp->os_open_ref_count++;
10580Sstevel@tonic-gate 				if (flag & FREAD)
10590Sstevel@tonic-gate 					osp->os_share_acc_read++;
10600Sstevel@tonic-gate 				if (flag & FWRITE)
10610Sstevel@tonic-gate 					osp->os_share_acc_write++;
10620Sstevel@tonic-gate 				osp->os_share_deny_none++;
10630Sstevel@tonic-gate 			}
10640Sstevel@tonic-gate 
10650Sstevel@tonic-gate 			/*
10660Sstevel@tonic-gate 			 * Need to reset this bitfield for the possible case
10670Sstevel@tonic-gate 			 * where we were going to OTW CLOSE the file, got a
10680Sstevel@tonic-gate 			 * non-recoverable error, and before we could retry
10690Sstevel@tonic-gate 			 * the CLOSE, OPENed the file again.
10700Sstevel@tonic-gate 			 */
10710Sstevel@tonic-gate 			ASSERT(osp->os_open_owner->oo_seqid_inuse);
10720Sstevel@tonic-gate 			osp->os_final_close = 0;
10730Sstevel@tonic-gate 			osp->os_force_close = 0;
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 			mutex_exit(&osp->os_sync_lock);
10760Sstevel@tonic-gate 			open_stream_rele(osp, rp);
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate #ifdef	DEBUG
10790Sstevel@tonic-gate 			bypass_otw[0]++;
10800Sstevel@tonic-gate #endif
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 			*errorp = 0;
10830Sstevel@tonic-gate 			return (0);
10840Sstevel@tonic-gate 		}
10850Sstevel@tonic-gate 		mutex_exit(&osp->os_sync_lock);
10860Sstevel@tonic-gate 		open_stream_rele(osp, rp);
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	} else if (dt != OPEN_DELEGATE_NONE) {
10890Sstevel@tonic-gate 		/*
10900Sstevel@tonic-gate 		 * Even if there isn't an open_stream yet, we may still be
10910Sstevel@tonic-gate 		 * able to bypass the otw open if the client owns a delegation.
10920Sstevel@tonic-gate 		 *
10930Sstevel@tonic-gate 		 * If you are asking for for WRITE, but I only have
10940Sstevel@tonic-gate 		 * a read delegation, then you still have to go otw.
10950Sstevel@tonic-gate 		 */
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 		if (flag & FWRITE && dt == OPEN_DELEGATE_READ)
10980Sstevel@tonic-gate 			return (1);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 		/*
11010Sstevel@tonic-gate 		 * TODO - evaluate the nfsace4
11020Sstevel@tonic-gate 		 */
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 		/*
11050Sstevel@tonic-gate 		 * Check the access flags to make sure the caller
11060Sstevel@tonic-gate 		 * had permission.
11070Sstevel@tonic-gate 		 */
11080Sstevel@tonic-gate 		if (flag & FREAD && !(acc & VREAD))
11090Sstevel@tonic-gate 			return (1);
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 		if (flag & FWRITE && !(acc & VWRITE))
11120Sstevel@tonic-gate 			return (1);
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 		/*
11150Sstevel@tonic-gate 		 * create_open_stream will add a reference to oop,
11160Sstevel@tonic-gate 		 * this will prevent the open_owner_rele done in
11170Sstevel@tonic-gate 		 * nfs4open_otw from destroying the open_owner.
11180Sstevel@tonic-gate 		 */
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 		/* returns with 'os_sync_lock' held */
11210Sstevel@tonic-gate 		osp = create_open_stream(oop, rp);
11220Sstevel@tonic-gate 		if (osp == NULL)
11230Sstevel@tonic-gate 			return (1);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate 		osp->open_stateid = rp->r_deleg_stateid;
11260Sstevel@tonic-gate 		osp->os_delegation = 1;
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 		if (flag & FREAD)
11290Sstevel@tonic-gate 			osp->os_share_acc_read++;
11300Sstevel@tonic-gate 		if (flag & FWRITE)
11310Sstevel@tonic-gate 			osp->os_share_acc_write++;
11320Sstevel@tonic-gate 
11330Sstevel@tonic-gate 		osp->os_share_deny_none++;
11340Sstevel@tonic-gate 		mutex_exit(&osp->os_sync_lock);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 		open_stream_rele(osp, rp);
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 		mutex_enter(&oop->oo_lock);
11390Sstevel@tonic-gate 		oop->oo_just_created = NFS4_PERM_CREATED;
11400Sstevel@tonic-gate 		mutex_exit(&oop->oo_lock);
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 		ASSERT(rsp != NULL);
11430Sstevel@tonic-gate 		if (rsp->rs_sp != NULL) {
11440Sstevel@tonic-gate 			mutex_enter(&rsp->rs_sp->s_lock);
11450Sstevel@tonic-gate 			nfs4_inc_state_ref_count_nolock(rsp->rs_sp,
11467902SNagakiran.Rajashekar@Sun.COM 			    VTOMI4(vp));
11470Sstevel@tonic-gate 			mutex_exit(&rsp->rs_sp->s_lock);
11480Sstevel@tonic-gate 		}
11490Sstevel@tonic-gate #ifdef	DEBUG
11500Sstevel@tonic-gate 		bypass_otw[1]++;
11510Sstevel@tonic-gate #endif
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 		*errorp = 0;
11540Sstevel@tonic-gate 		return (0);
11550Sstevel@tonic-gate 	}
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	return (1);
11580Sstevel@tonic-gate }
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate static open_delegation_type4
get_dtype(rnode4_t * rp)11610Sstevel@tonic-gate get_dtype(rnode4_t *rp)
11620Sstevel@tonic-gate {
11630Sstevel@tonic-gate 	open_delegation_type4 dt;
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	mutex_enter(&rp->r_statev4_lock);
11660Sstevel@tonic-gate 	ASSERT(!rp->r_deleg_return_inprog);
11670Sstevel@tonic-gate 	if (rp->r_deleg_return_pending)
11680Sstevel@tonic-gate 		dt = OPEN_DELEGATE_NONE;
11690Sstevel@tonic-gate 	else
11700Sstevel@tonic-gate 		dt = rp->r_deleg_type;
11710Sstevel@tonic-gate 	mutex_exit(&rp->r_statev4_lock);
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate 	return (dt);
11740Sstevel@tonic-gate }
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate /*
11770Sstevel@tonic-gate  * Fill in *locker with the lock state arguments for a LOCK call.  If
11780Sstevel@tonic-gate  * lop->lo_just_created == NFS4_JUST_CREATED, oop and osp must be non-NULL.
11790Sstevel@tonic-gate  * Caller must already hold the necessary seqid sync lock(s).
11800Sstevel@tonic-gate  */
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate void
nfs4_setup_lock_args(nfs4_lock_owner_t * lop,nfs4_open_owner_t * oop,nfs4_open_stream_t * osp,clientid4 clientid,locker4 * locker)11830Sstevel@tonic-gate nfs4_setup_lock_args(nfs4_lock_owner_t *lop, nfs4_open_owner_t *oop,
11840Sstevel@tonic-gate 	nfs4_open_stream_t *osp, clientid4 clientid, locker4 *locker)
11850Sstevel@tonic-gate {
11860Sstevel@tonic-gate 	ASSERT(lop->lo_flags & NFS4_LOCK_SEQID_INUSE);
11870Sstevel@tonic-gate 	if (lop->lo_just_created == NFS4_JUST_CREATED) {
11880Sstevel@tonic-gate 		/* this is a new lock request */
11890Sstevel@tonic-gate 		open_to_lock_owner4 *nown;
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 		ASSERT(oop != NULL);
11920Sstevel@tonic-gate 		ASSERT(osp != NULL);
11930Sstevel@tonic-gate 
11940Sstevel@tonic-gate 		locker->new_lock_owner = TRUE;
11950Sstevel@tonic-gate 		nown = &locker->locker4_u.open_owner;
11960Sstevel@tonic-gate 		nown->open_seqid = nfs4_get_open_seqid(oop) + 1;
11970Sstevel@tonic-gate 		mutex_enter(&osp->os_sync_lock);
11980Sstevel@tonic-gate 		nown->open_stateid = osp->open_stateid;
11990Sstevel@tonic-gate 		mutex_exit(&osp->os_sync_lock);
12000Sstevel@tonic-gate 		nown->lock_seqid = lop->lock_seqid; /* initial, so no +1 */
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 		nown->lock_owner.clientid = clientid;
12030Sstevel@tonic-gate 		nown->lock_owner.owner_len = sizeof (lop->lock_owner_name);
12040Sstevel@tonic-gate 		nown->lock_owner.owner_val =
12057902SNagakiran.Rajashekar@Sun.COM 		    kmem_alloc(nown->lock_owner.owner_len, KM_SLEEP);
12060Sstevel@tonic-gate 		bcopy(&lop->lock_owner_name, nown->lock_owner.owner_val,
12077902SNagakiran.Rajashekar@Sun.COM 		    nown->lock_owner.owner_len);
12080Sstevel@tonic-gate 	} else {
12090Sstevel@tonic-gate 		exist_lock_owner4 *eown;
12100Sstevel@tonic-gate 		/* have an existing lock owner */
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 		locker->new_lock_owner = FALSE;
12130Sstevel@tonic-gate 		eown = &locker->locker4_u.lock_owner;
12140Sstevel@tonic-gate 		mutex_enter(&lop->lo_lock);
12150Sstevel@tonic-gate 		eown->lock_stateid = lop->lock_stateid;
12160Sstevel@tonic-gate 		mutex_exit(&lop->lo_lock);
12170Sstevel@tonic-gate 		eown->lock_seqid = lop->lock_seqid + 1;
12180Sstevel@tonic-gate 	}
12190Sstevel@tonic-gate }
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate /*
12220Sstevel@tonic-gate  * This starts our use of the lock owner's lock seqid by setting
12230Sstevel@tonic-gate  * the lo_flags to NFS4_LOCK_SEQID_INUSE.  We will wait (forever)
12240Sstevel@tonic-gate  * with a cv_wait() until we are woken up.
12250Sstevel@tonic-gate  *
12260Sstevel@tonic-gate  * Return values:
12270Sstevel@tonic-gate  * 0		no problems
12280Sstevel@tonic-gate  * EAGAIN	caller should retry (like a recovery retry)
12290Sstevel@tonic-gate  */
12300Sstevel@tonic-gate int
nfs4_start_lock_seqid_sync(nfs4_lock_owner_t * lop,mntinfo4_t * mi)12310Sstevel@tonic-gate nfs4_start_lock_seqid_sync(nfs4_lock_owner_t *lop, mntinfo4_t *mi)
12320Sstevel@tonic-gate {
12330Sstevel@tonic-gate 	int error = 0;
12340Sstevel@tonic-gate #ifdef DEBUG
12350Sstevel@tonic-gate 	static int ops = 0;		/* fault injection */
12360Sstevel@tonic-gate #endif
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate #ifdef DEBUG
12390Sstevel@tonic-gate 	if (seqid_sync_faults && curthread != mi->mi_recovthread &&
12400Sstevel@tonic-gate 	    ++ops % 7 == 0)
12410Sstevel@tonic-gate 		return (EAGAIN);
12420Sstevel@tonic-gate #endif
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	mutex_enter(&mi->mi_lock);
12450Sstevel@tonic-gate 	if ((mi->mi_flags & MI4_RECOV_ACTIV) &&
12460Sstevel@tonic-gate 	    curthread != mi->mi_recovthread)
12470Sstevel@tonic-gate 		error = EAGAIN;
12480Sstevel@tonic-gate 	mutex_exit(&mi->mi_lock);
12490Sstevel@tonic-gate 	if (error != 0)
12500Sstevel@tonic-gate 		goto done;
12510Sstevel@tonic-gate 
12520Sstevel@tonic-gate 	mutex_enter(&lop->lo_lock);
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	ASSERT(lop->lo_seqid_holder != curthread);
12550Sstevel@tonic-gate 	while (lop->lo_flags & NFS4_LOCK_SEQID_INUSE) {
12560Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_seqid_sync, (CE_NOTE,
12577902SNagakiran.Rajashekar@Sun.COM 		    "nfs4_start_lock_seqid_sync: waiting on cv"));
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 		cv_wait(&lop->lo_cv_seqid_sync, &lop->lo_lock);
12600Sstevel@tonic-gate 	}
12610Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_seqid_sync, (CE_NOTE, "nfs4_start_lock_seqid_sync: "
12627902SNagakiran.Rajashekar@Sun.COM 	    "NFS4_LOCK_SEQID_INUSE"));
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	lop->lo_flags |= NFS4_LOCK_SEQID_INUSE;
12650Sstevel@tonic-gate 	lop->lo_seqid_holder = curthread;
12660Sstevel@tonic-gate 	mutex_exit(&lop->lo_lock);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	mutex_enter(&mi->mi_lock);
12690Sstevel@tonic-gate 	if ((mi->mi_flags & MI4_RECOV_ACTIV) &&
12700Sstevel@tonic-gate 	    curthread != mi->mi_recovthread)
12710Sstevel@tonic-gate 		error = EAGAIN;
12720Sstevel@tonic-gate 	mutex_exit(&mi->mi_lock);
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 	if (error == EAGAIN)
12750Sstevel@tonic-gate 		nfs4_end_lock_seqid_sync(lop);
12760Sstevel@tonic-gate 
12770Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_seqid_sync, (CE_NOTE,
12787902SNagakiran.Rajashekar@Sun.COM 	    "nfs4_start_lock_seqid_sync: error=%d", error));
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate done:
12810Sstevel@tonic-gate 	return (error);
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate /*
12850Sstevel@tonic-gate  * This ends our use of the lock owner's lock seqid by setting
12860Sstevel@tonic-gate  * the appropiate flags and issuing a cv_signal to wake up another
12870Sstevel@tonic-gate  * thread waiting to use the lock seqid.
12880Sstevel@tonic-gate  */
12890Sstevel@tonic-gate void
nfs4_end_lock_seqid_sync(nfs4_lock_owner_t * lop)12900Sstevel@tonic-gate nfs4_end_lock_seqid_sync(nfs4_lock_owner_t *lop)
12910Sstevel@tonic-gate {
12920Sstevel@tonic-gate 	mutex_enter(&lop->lo_lock);
12930Sstevel@tonic-gate 	ASSERT(lop->lo_flags & NFS4_LOCK_SEQID_INUSE);
12940Sstevel@tonic-gate 	ASSERT(lop->lo_seqid_holder == curthread);
12950Sstevel@tonic-gate 	lop->lo_flags &= ~NFS4_LOCK_SEQID_INUSE;
12960Sstevel@tonic-gate 	lop->lo_seqid_holder = NULL;
12970Sstevel@tonic-gate 	cv_broadcast(&lop->lo_cv_seqid_sync);
12980Sstevel@tonic-gate 	mutex_exit(&lop->lo_lock);
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate /*
13020Sstevel@tonic-gate  * Returns a reference to a lock owner via lopp, which has its lock seqid
13030Sstevel@tonic-gate  * synchronization started.
13040Sstevel@tonic-gate  * If the lock owner is in the 'just_created' state, then we return its open
13050Sstevel@tonic-gate  * owner and open stream and start the open seqid synchronization.
13060Sstevel@tonic-gate  *
13070Sstevel@tonic-gate  * Return value:
13080Sstevel@tonic-gate  * NFS4_OK		no problems
13090Sstevel@tonic-gate  * NFS4ERR_DELAY	there is lost state to recover; caller should retry
13100Sstevel@tonic-gate  * NFS4ERR_IO		no open stream
13110Sstevel@tonic-gate  */
13120Sstevel@tonic-gate nfsstat4
nfs4_find_or_create_lock_owner(pid_t pid,rnode4_t * rp,cred_t * cr,nfs4_open_owner_t ** oopp,nfs4_open_stream_t ** ospp,nfs4_lock_owner_t ** lopp)13130Sstevel@tonic-gate nfs4_find_or_create_lock_owner(pid_t pid, rnode4_t *rp, cred_t *cr,
13140Sstevel@tonic-gate 	nfs4_open_owner_t **oopp, nfs4_open_stream_t **ospp,
13150Sstevel@tonic-gate 	nfs4_lock_owner_t **lopp)
13160Sstevel@tonic-gate {
13170Sstevel@tonic-gate 	nfs4_lock_owner_t *lop, *next_lop;
13180Sstevel@tonic-gate 	mntinfo4_t *mi;
13190Sstevel@tonic-gate 	int error = 0;
13200Sstevel@tonic-gate 	nfsstat4 stat;
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	mi = VTOMI4(RTOV4(rp));
13230Sstevel@tonic-gate 
13240Sstevel@tonic-gate 	mutex_enter(&rp->r_statev4_lock);
13250Sstevel@tonic-gate 
13260Sstevel@tonic-gate 	lop = rp->r_lo_head.lo_next_rnode;
13270Sstevel@tonic-gate 	while (lop != &rp->r_lo_head) {
13280Sstevel@tonic-gate 		mutex_enter(&lop->lo_lock);
13290Sstevel@tonic-gate 		if (lop->lo_pid == pid && lop->lo_valid != 0) {
13300Sstevel@tonic-gate 			/* Found a matching lock owner */
13310Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_client_state_debug,
13327902SNagakiran.Rajashekar@Sun.COM 			    (CE_NOTE, "nfs4_find_or_create_lock_owner: "
13337902SNagakiran.Rajashekar@Sun.COM 			    "got a match"));
13340Sstevel@tonic-gate 			lop->lo_ref_count++;
13350Sstevel@tonic-gate 			break;
13360Sstevel@tonic-gate 		}
13370Sstevel@tonic-gate 		next_lop = lop->lo_next_rnode;
13380Sstevel@tonic-gate 		mutex_exit(&lop->lo_lock);
13390Sstevel@tonic-gate 		lop = next_lop;
13400Sstevel@tonic-gate 	}
13410Sstevel@tonic-gate 
13420Sstevel@tonic-gate 	if (lop == &rp->r_lo_head) {
13430Sstevel@tonic-gate 		/* create temporary lock owner */
13440Sstevel@tonic-gate 		lop = create_lock_owner(rp, pid);
13450Sstevel@tonic-gate 	}
13460Sstevel@tonic-gate 	mutex_exit(&rp->r_statev4_lock);
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	/* Have a locked down lock owner struct now */
13490Sstevel@tonic-gate 	if (lop->lo_just_created != NFS4_JUST_CREATED) {
13500Sstevel@tonic-gate 		/* This is an existing lock owner */
13510Sstevel@tonic-gate 		*oopp = NULL;
13520Sstevel@tonic-gate 		*ospp = NULL;
13530Sstevel@tonic-gate 	} else {
13540Sstevel@tonic-gate 		/* Lock owner doesn't exist yet */
13550Sstevel@tonic-gate 
13560Sstevel@tonic-gate 		/* First grab open owner seqid synchronization */
13570Sstevel@tonic-gate 		mutex_exit(&lop->lo_lock);
13580Sstevel@tonic-gate 		*oopp = find_open_owner(cr, NFS4_PERM_CREATED, mi);
13590Sstevel@tonic-gate 		if (*oopp == NULL)
13600Sstevel@tonic-gate 			goto kill_new_lop;
13610Sstevel@tonic-gate 		error = nfs4_start_open_seqid_sync(*oopp, mi);
13620Sstevel@tonic-gate 		if (error == EAGAIN) {
13630Sstevel@tonic-gate 			stat = NFS4ERR_DELAY;
13640Sstevel@tonic-gate 			goto failed;
13650Sstevel@tonic-gate 		}
13660Sstevel@tonic-gate 		*ospp = find_open_stream(*oopp, rp);
13670Sstevel@tonic-gate 		if (*ospp == NULL) {
13680Sstevel@tonic-gate 			nfs4_end_open_seqid_sync(*oopp);
13690Sstevel@tonic-gate 			goto kill_new_lop;
13700Sstevel@tonic-gate 		}
13710Sstevel@tonic-gate 		if ((*ospp)->os_failed_reopen) {
13720Sstevel@tonic-gate 			mutex_exit(&(*ospp)->os_sync_lock);
13730Sstevel@tonic-gate 			NFS4_DEBUG((nfs4_open_stream_debug ||
13747902SNagakiran.Rajashekar@Sun.COM 			    nfs4_client_lock_debug), (CE_NOTE,
13750Sstevel@tonic-gate 			    "nfs4_find_or_create_lock_owner: os_failed_reopen;"
13760Sstevel@tonic-gate 			    "osp %p, cr %p, rp %s", (void *)(*ospp),
13770Sstevel@tonic-gate 			    (void *)cr, rnode4info(rp)));
13780Sstevel@tonic-gate 			nfs4_end_open_seqid_sync(*oopp);
13790Sstevel@tonic-gate 			stat = NFS4ERR_IO;
13800Sstevel@tonic-gate 			goto failed;
13810Sstevel@tonic-gate 		}
13820Sstevel@tonic-gate 		mutex_exit(&(*ospp)->os_sync_lock);
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 		/*
13850Sstevel@tonic-gate 		 * Now see if the lock owner has become permanent while we
13860Sstevel@tonic-gate 		 * had released our lock.
13870Sstevel@tonic-gate 		 */
13880Sstevel@tonic-gate 		mutex_enter(&lop->lo_lock);
13890Sstevel@tonic-gate 		if (lop->lo_just_created != NFS4_JUST_CREATED) {
13900Sstevel@tonic-gate 			nfs4_end_open_seqid_sync(*oopp);
13910Sstevel@tonic-gate 			open_stream_rele(*ospp, rp);
13920Sstevel@tonic-gate 			open_owner_rele(*oopp);
13930Sstevel@tonic-gate 			*oopp = NULL;
13940Sstevel@tonic-gate 			*ospp = NULL;
13950Sstevel@tonic-gate 		}
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 	mutex_exit(&lop->lo_lock);
13980Sstevel@tonic-gate 
13990Sstevel@tonic-gate 	error = nfs4_start_lock_seqid_sync(lop, mi);
14000Sstevel@tonic-gate 	if (error == EAGAIN) {
14010Sstevel@tonic-gate 		if (*oopp != NULL)
14020Sstevel@tonic-gate 			nfs4_end_open_seqid_sync(*oopp);
14030Sstevel@tonic-gate 		stat = NFS4ERR_DELAY;
14040Sstevel@tonic-gate 		goto failed;
14050Sstevel@tonic-gate 	}
14060Sstevel@tonic-gate 	ASSERT(error == 0);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	*lopp = lop;
14090Sstevel@tonic-gate 	return (NFS4_OK);
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate kill_new_lop:
14120Sstevel@tonic-gate 	/*
14130Sstevel@tonic-gate 	 * A previous CLOSE was attempted but got EINTR, but the application
14140Sstevel@tonic-gate 	 * continued to use the unspecified state file descriptor.  But now the
14150Sstevel@tonic-gate 	 * open stream is gone (which could also destroy the open owner), hence
14160Sstevel@tonic-gate 	 * we can no longer continue.  The calling function should return EIO
14170Sstevel@tonic-gate 	 * to the application.
14180Sstevel@tonic-gate 	 */
14190Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_lost_rqst_debug || nfs4_client_lock_debug,
14200Sstevel@tonic-gate 	    (CE_NOTE, "nfs4_find_or_create_lock_owner: destroy newly created "
14210Sstevel@tonic-gate 	    "lop %p, oop %p, osp %p", (void *)lop, (void *)(*oopp),
14220Sstevel@tonic-gate 	    (void *)(*ospp)));
14230Sstevel@tonic-gate 
14240Sstevel@tonic-gate 	nfs4_rnode_remove_lock_owner(rp, lop);
14250Sstevel@tonic-gate 	stat = NFS4ERR_IO;
14260Sstevel@tonic-gate 
14270Sstevel@tonic-gate failed:
14280Sstevel@tonic-gate 	lock_owner_rele(lop);
14290Sstevel@tonic-gate 	if (*oopp) {
14300Sstevel@tonic-gate 		open_owner_rele(*oopp);
14310Sstevel@tonic-gate 		*oopp = NULL;
14320Sstevel@tonic-gate 	}
14330Sstevel@tonic-gate 	if (*ospp) {
14340Sstevel@tonic-gate 		open_stream_rele(*ospp, rp);
14350Sstevel@tonic-gate 		*ospp = NULL;
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 	return (stat);
14380Sstevel@tonic-gate }
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate /*
14410Sstevel@tonic-gate  * This function grabs a recently freed open owner off of the freed open
14420Sstevel@tonic-gate  * owner list if there is a match on the cred 'cr'.  It returns NULL if no
14430Sstevel@tonic-gate  * such match is found.  It will set the 'oo_ref_count' and 'oo_valid' back
14440Sstevel@tonic-gate  * to both 1 (sane values) in the case a match is found.
14450Sstevel@tonic-gate  */
14460Sstevel@tonic-gate static nfs4_open_owner_t *
find_freed_open_owner(cred_t * cr,nfs4_oo_hash_bucket_t * bucketp,mntinfo4_t * mi)14470Sstevel@tonic-gate find_freed_open_owner(cred_t *cr, nfs4_oo_hash_bucket_t *bucketp,
14480Sstevel@tonic-gate 	mntinfo4_t *mi)
14490Sstevel@tonic-gate {
14500Sstevel@tonic-gate 	nfs4_open_owner_t		*foop;
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_state_debug, (CE_NOTE,
14537902SNagakiran.Rajashekar@Sun.COM 	    "find_freed_open_owner: cred %p", (void*)cr));
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 	ASSERT(mutex_owned(&mi->mi_lock));
14560Sstevel@tonic-gate 	ASSERT(mutex_owned(&bucketp->b_lock));
14570Sstevel@tonic-gate 
14580Sstevel@tonic-gate 	/* got hash bucket, search through freed open owners */
14590Sstevel@tonic-gate 	for (foop = list_head(&mi->mi_foo_list); foop != NULL;
14600Sstevel@tonic-gate 	    foop = list_next(&mi->mi_foo_list, foop)) {
14610Sstevel@tonic-gate 		if (!crcmp(foop->oo_cred, cr)) {
14620Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_client_foo_debug, (CE_NOTE,
14637902SNagakiran.Rajashekar@Sun.COM 			    "find_freed_open_owner: got a match open owner "
14647902SNagakiran.Rajashekar@Sun.COM 			    "%p", (void *)foop));
14650Sstevel@tonic-gate 			foop->oo_ref_count = 1;
14660Sstevel@tonic-gate 			foop->oo_valid = 1;
14670Sstevel@tonic-gate 			list_remove(&mi->mi_foo_list, foop);
14680Sstevel@tonic-gate 			mi->mi_foo_num--;
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 			/* now add the struct into the cred hash table */
14710Sstevel@tonic-gate 			list_insert_head(&bucketp->b_oo_hash_list, foop);
14720Sstevel@tonic-gate 			return (foop);
14730Sstevel@tonic-gate 		}
14740Sstevel@tonic-gate 	}
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	return (NULL);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate /*
14800Sstevel@tonic-gate  * Insert the newly freed 'oop' into the mi's freed oop list,
14810Sstevel@tonic-gate  * always at the head of the list.  If we've already reached
14820Sstevel@tonic-gate  * our maximum allowed number of freed open owners (mi_foo_max),
14830Sstevel@tonic-gate  * then remove the LRU open owner on the list (namely the tail).
14840Sstevel@tonic-gate  */
14850Sstevel@tonic-gate static void
nfs4_free_open_owner(nfs4_open_owner_t * oop,mntinfo4_t * mi)14860Sstevel@tonic-gate nfs4_free_open_owner(nfs4_open_owner_t *oop, mntinfo4_t *mi)
14870Sstevel@tonic-gate {
14880Sstevel@tonic-gate 	nfs4_open_owner_t *lru_foop;
14890Sstevel@tonic-gate 
14900Sstevel@tonic-gate 	if (mi->mi_foo_num < mi->mi_foo_max) {
14910Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_foo_debug, (CE_NOTE,
14927902SNagakiran.Rajashekar@Sun.COM 		    "nfs4_free_open_owner: num free %d, max free %d, "
14937902SNagakiran.Rajashekar@Sun.COM 		    "insert open owner %p for mntinfo4 %p",
14947902SNagakiran.Rajashekar@Sun.COM 		    mi->mi_foo_num, mi->mi_foo_max, (void *)oop,
14957902SNagakiran.Rajashekar@Sun.COM 		    (void *)mi));
14960Sstevel@tonic-gate 		list_insert_head(&mi->mi_foo_list, oop);
14970Sstevel@tonic-gate 		mi->mi_foo_num++;
14980Sstevel@tonic-gate 		return;
14990Sstevel@tonic-gate 	}
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	/* need to replace a freed open owner */
15020Sstevel@tonic-gate 
15030Sstevel@tonic-gate 	lru_foop = list_tail(&mi->mi_foo_list);
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_foo_debug, (CE_NOTE,
15060Sstevel@tonic-gate 	    "nfs4_free_open_owner: destroy %p, insert %p",
15070Sstevel@tonic-gate 	    (void *)lru_foop, (void *)oop));
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 	list_remove(&mi->mi_foo_list, lru_foop);
15100Sstevel@tonic-gate 	nfs4_destroy_open_owner(lru_foop);
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	/* head always has latest freed oop */
15130Sstevel@tonic-gate 	list_insert_head(&mi->mi_foo_list, oop);
15140Sstevel@tonic-gate }
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate void
nfs4_destroy_open_owner(nfs4_open_owner_t * oop)15170Sstevel@tonic-gate nfs4_destroy_open_owner(nfs4_open_owner_t *oop)
15180Sstevel@tonic-gate {
15190Sstevel@tonic-gate 	ASSERT(oop != NULL);
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 	crfree(oop->oo_cred);
15220Sstevel@tonic-gate 	if (oop->oo_cred_otw)
15230Sstevel@tonic-gate 		crfree(oop->oo_cred_otw);
15240Sstevel@tonic-gate 	mutex_destroy(&oop->oo_lock);
15250Sstevel@tonic-gate 	cv_destroy(&oop->oo_cv_seqid_sync);
15260Sstevel@tonic-gate 	kmem_free(oop, sizeof (*oop));
15270Sstevel@tonic-gate }
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate seqid4
nfs4_get_open_seqid(nfs4_open_owner_t * oop)15300Sstevel@tonic-gate nfs4_get_open_seqid(nfs4_open_owner_t *oop)
15310Sstevel@tonic-gate {
15320Sstevel@tonic-gate 	ASSERT(oop->oo_seqid_inuse);
15330Sstevel@tonic-gate 	return (oop->oo_seqid);
15340Sstevel@tonic-gate }
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate /*
15370Sstevel@tonic-gate  * This set's the open seqid for a <open owner/ mntinfo4> pair.
15380Sstevel@tonic-gate  */
15390Sstevel@tonic-gate void
nfs4_set_open_seqid(seqid4 seqid,nfs4_open_owner_t * oop,nfs4_tag_type_t tag_type)15400Sstevel@tonic-gate nfs4_set_open_seqid(seqid4 seqid, nfs4_open_owner_t *oop,
15410Sstevel@tonic-gate 	nfs4_tag_type_t tag_type)
15420Sstevel@tonic-gate {
15430Sstevel@tonic-gate 	ASSERT(oop->oo_seqid_inuse);
15440Sstevel@tonic-gate 	oop->oo_seqid = seqid;
15450Sstevel@tonic-gate 	oop->oo_last_good_seqid = seqid;
15460Sstevel@tonic-gate 	oop->oo_last_good_op = tag_type;
15470Sstevel@tonic-gate }
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate /*
15500Sstevel@tonic-gate  * This bumps the current open seqid for the open owner 'oop'.
15510Sstevel@tonic-gate  */
15520Sstevel@tonic-gate void
nfs4_get_and_set_next_open_seqid(nfs4_open_owner_t * oop,nfs4_tag_type_t tag_type)15530Sstevel@tonic-gate nfs4_get_and_set_next_open_seqid(nfs4_open_owner_t *oop,
15540Sstevel@tonic-gate     nfs4_tag_type_t tag_type)
15550Sstevel@tonic-gate {
15560Sstevel@tonic-gate 	ASSERT(oop->oo_seqid_inuse);
15570Sstevel@tonic-gate 	oop->oo_seqid++;
15580Sstevel@tonic-gate 	oop->oo_last_good_seqid = oop->oo_seqid;
15590Sstevel@tonic-gate 	oop->oo_last_good_op = tag_type;
15600Sstevel@tonic-gate }
15610Sstevel@tonic-gate 
15620Sstevel@tonic-gate /*
15630Sstevel@tonic-gate  * If no open owner was provided, this function takes the cred to find an
15640Sstevel@tonic-gate  * open owner within the given mntinfo4_t.  Either way we return the
15650Sstevel@tonic-gate  * open owner's OTW credential if it exists; otherwise returns the
15660Sstevel@tonic-gate  * supplied 'cr'.
15670Sstevel@tonic-gate  *
15680Sstevel@tonic-gate  * A hold is put on the returned credential, and it is up to the caller
15690Sstevel@tonic-gate  * to free the cred.
15700Sstevel@tonic-gate  */
15710Sstevel@tonic-gate cred_t *
nfs4_get_otw_cred(cred_t * cr,mntinfo4_t * mi,nfs4_open_owner_t * provided_oop)15720Sstevel@tonic-gate nfs4_get_otw_cred(cred_t *cr, mntinfo4_t *mi, nfs4_open_owner_t *provided_oop)
15730Sstevel@tonic-gate {
15740Sstevel@tonic-gate 	cred_t *ret_cr;
15750Sstevel@tonic-gate 	nfs4_open_owner_t *oop = provided_oop;
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 	if (oop == NULL)
15780Sstevel@tonic-gate 		oop = find_open_owner(cr, NFS4_PERM_CREATED, mi);
15790Sstevel@tonic-gate 	if (oop != NULL) {
15800Sstevel@tonic-gate 		mutex_enter(&oop->oo_lock);
15810Sstevel@tonic-gate 		if (oop->oo_cred_otw)
15820Sstevel@tonic-gate 			ret_cr = oop->oo_cred_otw;
15830Sstevel@tonic-gate 		else
15840Sstevel@tonic-gate 			ret_cr = cr;
15850Sstevel@tonic-gate 		crhold(ret_cr);
15860Sstevel@tonic-gate 		mutex_exit(&oop->oo_lock);
15870Sstevel@tonic-gate 		if (provided_oop == NULL)
15880Sstevel@tonic-gate 			open_owner_rele(oop);
15890Sstevel@tonic-gate 	} else {
15900Sstevel@tonic-gate 		ret_cr = cr;
15910Sstevel@tonic-gate 		crhold(ret_cr);
15920Sstevel@tonic-gate 	}
15930Sstevel@tonic-gate 	return (ret_cr);
15940Sstevel@tonic-gate }
15950Sstevel@tonic-gate 
15960Sstevel@tonic-gate /*
15970Sstevel@tonic-gate  * Retrieves the next open stream in the rnode's list if an open stream
15980Sstevel@tonic-gate  * is provided; otherwise gets the first open stream in the list.
15990Sstevel@tonic-gate  * The open owner for that open stream is then retrieved, and if its
16000Sstevel@tonic-gate  * oo_cred_otw exists then it is returned; otherwise the provided 'cr'
16010Sstevel@tonic-gate  * is returned.  *osp is set to the 'found' open stream.
16020Sstevel@tonic-gate  *
16030Sstevel@tonic-gate  * Note: we don't set *osp to the open stream retrieved via the
16040Sstevel@tonic-gate  * optimized check since that won't necessarily be at the beginning
16050Sstevel@tonic-gate  * of the rnode list, and if that osp doesn't work we'd like to
16060Sstevel@tonic-gate  * check _all_ open streams (starting from the beginning of the
16070Sstevel@tonic-gate  * rnode list).
16080Sstevel@tonic-gate  */
16090Sstevel@tonic-gate cred_t *
nfs4_get_otw_cred_by_osp(rnode4_t * rp,cred_t * cr,nfs4_open_stream_t ** osp,bool_t * first_time,bool_t * last_time)16100Sstevel@tonic-gate nfs4_get_otw_cred_by_osp(rnode4_t *rp, cred_t *cr,
16110Sstevel@tonic-gate 	nfs4_open_stream_t **osp, bool_t *first_time, bool_t *last_time)
16120Sstevel@tonic-gate {
16130Sstevel@tonic-gate 	nfs4_open_stream_t *next_osp = NULL;
16140Sstevel@tonic-gate 	cred_t *ret_cr;
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	ASSERT(cr != NULL);
16170Sstevel@tonic-gate 	/*
16180Sstevel@tonic-gate 	 * As an optimization, try to find the open owner
16190Sstevel@tonic-gate 	 * for the cred provided since that's most likely
16200Sstevel@tonic-gate 	 * to work.
16210Sstevel@tonic-gate 	 */
16220Sstevel@tonic-gate 	if (*first_time) {
16230Sstevel@tonic-gate 		nfs4_open_owner_t *oop;
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 		oop = find_open_owner(cr, NFS4_PERM_CREATED, VTOMI4(RTOV4(rp)));
16260Sstevel@tonic-gate 		if (oop) {
16270Sstevel@tonic-gate 			next_osp = find_open_stream(oop, rp);
16280Sstevel@tonic-gate 			if (next_osp)
16290Sstevel@tonic-gate 				mutex_exit(&next_osp->os_sync_lock);
16300Sstevel@tonic-gate 			open_owner_rele(oop);
16310Sstevel@tonic-gate 		}
1632*7981SGerald.Thornbrugh@Sun.COM 	}
1633*7981SGerald.Thornbrugh@Sun.COM 	if (next_osp == NULL) {
16340Sstevel@tonic-gate 		int delay_rele = 0;
1635*7981SGerald.Thornbrugh@Sun.COM 		*first_time = FALSE;
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 		/* return the next open stream for this rnode */
16380Sstevel@tonic-gate 		mutex_enter(&rp->r_os_lock);
16390Sstevel@tonic-gate 		/* Now, no one can add or delete to rp's open streams list */
16400Sstevel@tonic-gate 
16410Sstevel@tonic-gate 		if (*osp) {
16420Sstevel@tonic-gate 			next_osp = list_next(&rp->r_open_streams, *osp);
16430Sstevel@tonic-gate 			/*
16440Sstevel@tonic-gate 			 * Delay the rele of *osp until after we drop
16450Sstevel@tonic-gate 			 * r_os_lock to not deadlock with oo_lock
16460Sstevel@tonic-gate 			 * via an open_stream_rele()->open_owner_rele().
16470Sstevel@tonic-gate 			 */
16480Sstevel@tonic-gate 			delay_rele = 1;
16490Sstevel@tonic-gate 		} else {
16500Sstevel@tonic-gate 			next_osp = list_head(&rp->r_open_streams);
16510Sstevel@tonic-gate 		}
16520Sstevel@tonic-gate 		if (next_osp) {
16530Sstevel@tonic-gate 			nfs4_open_stream_t *tmp_osp;
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 			/* find the next valid open stream */
16560Sstevel@tonic-gate 			mutex_enter(&next_osp->os_sync_lock);
16570Sstevel@tonic-gate 			while (next_osp && !next_osp->os_valid) {
16580Sstevel@tonic-gate 				tmp_osp =
16590Sstevel@tonic-gate 				    list_next(&rp->r_open_streams, next_osp);
16600Sstevel@tonic-gate 				mutex_exit(&next_osp->os_sync_lock);
16610Sstevel@tonic-gate 				next_osp = tmp_osp;
16620Sstevel@tonic-gate 				if (next_osp)
16630Sstevel@tonic-gate 					mutex_enter(&next_osp->os_sync_lock);
16640Sstevel@tonic-gate 			}
16650Sstevel@tonic-gate 			if (next_osp) {
16660Sstevel@tonic-gate 				next_osp->os_ref_count++;
16670Sstevel@tonic-gate 				mutex_exit(&next_osp->os_sync_lock);
16680Sstevel@tonic-gate 			}
16690Sstevel@tonic-gate 		}
16700Sstevel@tonic-gate 		mutex_exit(&rp->r_os_lock);
16710Sstevel@tonic-gate 		if (delay_rele)
16720Sstevel@tonic-gate 			open_stream_rele(*osp, rp);
16730Sstevel@tonic-gate 	}
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 	if (next_osp) {
16760Sstevel@tonic-gate 		nfs4_open_owner_t *oop;
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 		oop = next_osp->os_open_owner;
16790Sstevel@tonic-gate 		mutex_enter(&oop->oo_lock);
16800Sstevel@tonic-gate 		if (oop->oo_cred_otw)
16810Sstevel@tonic-gate 			ret_cr = oop->oo_cred_otw;
16820Sstevel@tonic-gate 		else
16830Sstevel@tonic-gate 			ret_cr = cr;
16840Sstevel@tonic-gate 		crhold(ret_cr);
16850Sstevel@tonic-gate 		mutex_exit(&oop->oo_lock);
16860Sstevel@tonic-gate 		if (*first_time) {
16870Sstevel@tonic-gate 			open_stream_rele(next_osp, rp);
16880Sstevel@tonic-gate 			*osp = NULL;
16890Sstevel@tonic-gate 		} else
16900Sstevel@tonic-gate 			*osp = next_osp;
16910Sstevel@tonic-gate 	} else {
16920Sstevel@tonic-gate 		/* just return the cred provided to us */
1693*7981SGerald.Thornbrugh@Sun.COM 		*last_time = TRUE;
16940Sstevel@tonic-gate 		*osp = NULL;
16950Sstevel@tonic-gate 		ret_cr = cr;
16960Sstevel@tonic-gate 		crhold(ret_cr);
16970Sstevel@tonic-gate 	}
16980Sstevel@tonic-gate 
1699*7981SGerald.Thornbrugh@Sun.COM 	*first_time = FALSE;
17000Sstevel@tonic-gate 	return (ret_cr);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate void
nfs4_init_stateid_types(nfs4_stateid_types_t * sid_tp)17040Sstevel@tonic-gate nfs4_init_stateid_types(nfs4_stateid_types_t *sid_tp)
17050Sstevel@tonic-gate {
17060Sstevel@tonic-gate 	bzero(&sid_tp->d_sid, sizeof (stateid4));
17070Sstevel@tonic-gate 	bzero(&sid_tp->l_sid, sizeof (stateid4));
17080Sstevel@tonic-gate 	bzero(&sid_tp->o_sid, sizeof (stateid4));
17090Sstevel@tonic-gate 	sid_tp->cur_sid_type = NO_SID;
17100Sstevel@tonic-gate }
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate void
nfs4_save_stateid(stateid4 * s1,nfs4_stateid_types_t * sid_tp)17130Sstevel@tonic-gate nfs4_save_stateid(stateid4 *s1, nfs4_stateid_types_t *sid_tp)
17140Sstevel@tonic-gate {
17150Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_recov_debug, (CE_NOTE,
17160Sstevel@tonic-gate 	    "nfs4_save_stateid: saved %s stateid",
17170Sstevel@tonic-gate 	    sid_tp->cur_sid_type == DEL_SID ? "delegation" :
17180Sstevel@tonic-gate 	    sid_tp->cur_sid_type == LOCK_SID ? "lock" :
17190Sstevel@tonic-gate 	    sid_tp->cur_sid_type == OPEN_SID ? "open" : "special"));
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	switch (sid_tp->cur_sid_type) {
17220Sstevel@tonic-gate 	case DEL_SID:
17230Sstevel@tonic-gate 		sid_tp->d_sid = *s1;
17240Sstevel@tonic-gate 		break;
17250Sstevel@tonic-gate 	case LOCK_SID:
17260Sstevel@tonic-gate 		sid_tp->l_sid = *s1;
17270Sstevel@tonic-gate 		break;
17280Sstevel@tonic-gate 	case OPEN_SID:
17290Sstevel@tonic-gate 		sid_tp->o_sid = *s1;
17300Sstevel@tonic-gate 		break;
17310Sstevel@tonic-gate 	case SPEC_SID:
17320Sstevel@tonic-gate 	default:
17330Sstevel@tonic-gate 		cmn_err(CE_PANIC, "nfs4_save_stateid: illegal "
17340Sstevel@tonic-gate 		    "stateid type %d", sid_tp->cur_sid_type);
17350Sstevel@tonic-gate 	}
17360Sstevel@tonic-gate }
17370Sstevel@tonic-gate 
17380Sstevel@tonic-gate /*
17390Sstevel@tonic-gate  * We got NFS4ERR_BAD_SEQID.  Setup some arguments to pass to recovery.
17400Sstevel@tonic-gate  * Caller is responsible for freeing.
17410Sstevel@tonic-gate  */
17420Sstevel@tonic-gate nfs4_bseqid_entry_t *
nfs4_create_bseqid_entry(nfs4_open_owner_t * oop,nfs4_lock_owner_t * lop,vnode_t * vp,pid_t pid,nfs4_tag_type_t tag,seqid4 seqid)17430Sstevel@tonic-gate nfs4_create_bseqid_entry(nfs4_open_owner_t *oop, nfs4_lock_owner_t *lop,
17440Sstevel@tonic-gate     vnode_t *vp, pid_t pid, nfs4_tag_type_t tag, seqid4 seqid)
17450Sstevel@tonic-gate {
17460Sstevel@tonic-gate 	nfs4_bseqid_entry_t	*bsep;
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 	bsep = kmem_alloc(sizeof (*bsep), KM_SLEEP);
17490Sstevel@tonic-gate 	bsep->bs_oop = oop;
17500Sstevel@tonic-gate 	bsep->bs_lop = lop;
17510Sstevel@tonic-gate 	bsep->bs_vp = vp;
17520Sstevel@tonic-gate 	bsep->bs_pid = pid;
17530Sstevel@tonic-gate 	bsep->bs_tag = tag;
17540Sstevel@tonic-gate 	bsep->bs_seqid = seqid;
17550Sstevel@tonic-gate 
17560Sstevel@tonic-gate 	return (bsep);
17570Sstevel@tonic-gate }
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate void
nfs4open_dg_save_lost_rqst(int error,nfs4_lost_rqst_t * lost_rqstp,nfs4_open_owner_t * oop,nfs4_open_stream_t * osp,cred_t * cr,vnode_t * vp,int access_close,int deny_close)17600Sstevel@tonic-gate nfs4open_dg_save_lost_rqst(int error, nfs4_lost_rqst_t *lost_rqstp,
17610Sstevel@tonic-gate 	nfs4_open_owner_t *oop, nfs4_open_stream_t *osp, cred_t *cr,
17620Sstevel@tonic-gate 	vnode_t *vp, int access_close, int deny_close)
17630Sstevel@tonic-gate {
17640Sstevel@tonic-gate 	lost_rqstp->lr_putfirst = FALSE;
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 	ASSERT(vp != NULL);
17670Sstevel@tonic-gate 	if (error == ETIMEDOUT || error == EINTR ||
17680Sstevel@tonic-gate 	    NFS4_FRC_UNMT_ERR(error, vp->v_vfsp)) {
17690Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
17707902SNagakiran.Rajashekar@Sun.COM 		    "nfs4open_dg_save_lost_rqst: error %d", error));
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 		lost_rqstp->lr_op = OP_OPEN_DOWNGRADE;
17730Sstevel@tonic-gate 		/*
17740Sstevel@tonic-gate 		 * The vp is held and rele'd via the recovery code.
17750Sstevel@tonic-gate 		 * See nfs4_save_lost_rqst.
17760Sstevel@tonic-gate 		 */
17770Sstevel@tonic-gate 		lost_rqstp->lr_vp = vp;
17780Sstevel@tonic-gate 		lost_rqstp->lr_dvp = NULL;
17790Sstevel@tonic-gate 		lost_rqstp->lr_oop = oop;
17800Sstevel@tonic-gate 		lost_rqstp->lr_osp = osp;
17810Sstevel@tonic-gate 		lost_rqstp->lr_lop = NULL;
17820Sstevel@tonic-gate 		lost_rqstp->lr_cr = cr;
17830Sstevel@tonic-gate 		lost_rqstp->lr_flk = NULL;
17840Sstevel@tonic-gate 		lost_rqstp->lr_dg_acc = access_close;
17850Sstevel@tonic-gate 		lost_rqstp->lr_dg_deny = deny_close;
17860Sstevel@tonic-gate 		lost_rqstp->lr_putfirst = FALSE;
17870Sstevel@tonic-gate 	} else {
17880Sstevel@tonic-gate 		lost_rqstp->lr_op = 0;
17890Sstevel@tonic-gate 	}
17900Sstevel@tonic-gate }
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate /*
17930Sstevel@tonic-gate  * Change the access and deny bits of an OPEN.
17940Sstevel@tonic-gate  * If recovery is needed, *recov_credpp is set to the cred used OTW,
17950Sstevel@tonic-gate  * a hold is placed on it, and *recov_seqidp is set to the seqid used OTW.
17960Sstevel@tonic-gate  */
17970Sstevel@tonic-gate void
nfs4_open_downgrade(int access_close,int deny_close,nfs4_open_owner_t * oop,nfs4_open_stream_t * osp,vnode_t * vp,cred_t * cr,nfs4_lost_rqst_t * lrp,nfs4_error_t * ep,cred_t ** recov_credpp,seqid4 * recov_seqidp)17980Sstevel@tonic-gate nfs4_open_downgrade(int access_close, int deny_close, nfs4_open_owner_t *oop,
17990Sstevel@tonic-gate 	nfs4_open_stream_t *osp, vnode_t *vp, cred_t *cr, nfs4_lost_rqst_t *lrp,
18000Sstevel@tonic-gate 	nfs4_error_t *ep, cred_t **recov_credpp, seqid4 *recov_seqidp)
18010Sstevel@tonic-gate {
18020Sstevel@tonic-gate 	mntinfo4_t		*mi;
18030Sstevel@tonic-gate 	int			downgrade_acc, downgrade_deny;
18040Sstevel@tonic-gate 	int			new_acc, new_deny;
18050Sstevel@tonic-gate 	COMPOUND4args_clnt	args;
18060Sstevel@tonic-gate 	COMPOUND4res_clnt	res;
18070Sstevel@tonic-gate 	OPEN_DOWNGRADE4res	*odg_res;
18080Sstevel@tonic-gate 	nfs_argop4		argop[3];
18090Sstevel@tonic-gate 	nfs_resop4		*resop;
18100Sstevel@tonic-gate 	rnode4_t		*rp;
18110Sstevel@tonic-gate 	bool_t			needrecov = FALSE;
18120Sstevel@tonic-gate 	int			doqueue = 1;
18130Sstevel@tonic-gate 	seqid4			seqid = 0;
18140Sstevel@tonic-gate 	cred_t			*cred_otw;
18150Sstevel@tonic-gate 	hrtime_t		t;
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 	ASSERT(mutex_owned(&osp->os_sync_lock));
18180Sstevel@tonic-gate #if DEBUG
18190Sstevel@tonic-gate 	mutex_enter(&oop->oo_lock);
18200Sstevel@tonic-gate 	ASSERT(oop->oo_seqid_inuse);
18210Sstevel@tonic-gate 	mutex_exit(&oop->oo_lock);
18220Sstevel@tonic-gate #endif
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 	if (access_close == 0 && deny_close == 0) {
18260Sstevel@tonic-gate 		nfs4_error_zinit(ep);
18270Sstevel@tonic-gate 		return;
18280Sstevel@tonic-gate 	}
18290Sstevel@tonic-gate 
18300Sstevel@tonic-gate 	cred_otw = nfs4_get_otw_cred(cr, VTOMI4(vp), oop);
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate cred_retry:
18330Sstevel@tonic-gate 	nfs4_error_zinit(ep);
18340Sstevel@tonic-gate 	downgrade_acc = 0;
18350Sstevel@tonic-gate 	downgrade_deny = 0;
18360Sstevel@tonic-gate 	mi = VTOMI4(vp);
18370Sstevel@tonic-gate 	rp = VTOR4(vp);
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	/*
18400Sstevel@tonic-gate 	 * Check to see if the open stream got closed before we go OTW,
18410Sstevel@tonic-gate 	 * now that we have acquired the 'os_sync_lock'.
18420Sstevel@tonic-gate 	 */
18430Sstevel@tonic-gate 	if (!osp->os_valid) {
18440Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_open_dg, (CE_NOTE, "nfs4_open_downgrade:"
18450Sstevel@tonic-gate 		    " open stream has already been closed, return success"));
18460Sstevel@tonic-gate 		/* error has already been set */
18470Sstevel@tonic-gate 		goto no_args_out;
18480Sstevel@tonic-gate 	}
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 	/* If the file failed recovery, just quit. */
18510Sstevel@tonic-gate 	mutex_enter(&rp->r_statelock);
18520Sstevel@tonic-gate 	if (rp->r_flags & R4RECOVERR) {
18530Sstevel@tonic-gate 		mutex_exit(&rp->r_statelock);
18540Sstevel@tonic-gate 		ep->error = EIO;
18550Sstevel@tonic-gate 		goto no_args_out;
18560Sstevel@tonic-gate 	}
18570Sstevel@tonic-gate 	mutex_exit(&rp->r_statelock);
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	seqid = nfs4_get_open_seqid(oop) + 1;
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_open_dg, (CE_NOTE, "nfs4_open_downgrade:"
18620Sstevel@tonic-gate 	    "access_close %d, acc_read %"PRIu64" acc_write %"PRIu64"",
18630Sstevel@tonic-gate 	    access_close, osp->os_share_acc_read, osp->os_share_acc_write));
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 	/* If we're closing the last READ, need to downgrade */
18660Sstevel@tonic-gate 	if ((access_close & FREAD) && (osp->os_share_acc_read == 1))
18670Sstevel@tonic-gate 		downgrade_acc |= OPEN4_SHARE_ACCESS_READ;
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	/* if we're closing the last WRITE, need to downgrade */
18700Sstevel@tonic-gate 	if ((access_close & FWRITE) && (osp->os_share_acc_write == 1))
18710Sstevel@tonic-gate 		downgrade_acc |= OPEN4_SHARE_ACCESS_WRITE;
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 	downgrade_deny = OPEN4_SHARE_DENY_NONE;
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate 	new_acc = 0;
18760Sstevel@tonic-gate 	new_deny = 0;
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 	/* set our new access and deny share bits */
18790Sstevel@tonic-gate 	if ((osp->os_share_acc_read > 0) &&
18800Sstevel@tonic-gate 	    !(downgrade_acc & OPEN4_SHARE_ACCESS_READ))
18810Sstevel@tonic-gate 		new_acc |= OPEN4_SHARE_ACCESS_READ;
18820Sstevel@tonic-gate 	if ((osp->os_share_acc_write > 0) &&
18830Sstevel@tonic-gate 	    !(downgrade_acc & OPEN4_SHARE_ACCESS_WRITE))
18840Sstevel@tonic-gate 		new_acc |= OPEN4_SHARE_ACCESS_WRITE;
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	new_deny = OPEN4_SHARE_DENY_NONE;
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_open_dg, (CE_NOTE, "nfs4_open_downgrade:"
18890Sstevel@tonic-gate 	    "downgrade acc 0x%x deny 0x%x", downgrade_acc, downgrade_deny));
18900Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_client_open_dg, (CE_NOTE, "nfs4_open_downgrade:"
18910Sstevel@tonic-gate 	    "new acc 0x%x deny 0x%x", new_acc, new_deny));
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 	/*
18940Sstevel@tonic-gate 	 * Check to see if we aren't actually doing any downgrade or
18950Sstevel@tonic-gate 	 * if this is the last 'close' but the file is still mmapped.
18960Sstevel@tonic-gate 	 * Skip this if this a lost request resend so we don't decrement
18970Sstevel@tonic-gate 	 * the osp's share counts more than once.
18980Sstevel@tonic-gate 	 */
18990Sstevel@tonic-gate 	if (!lrp &&
19000Sstevel@tonic-gate 	    ((downgrade_acc == 0 && downgrade_deny == 0) ||
19010Sstevel@tonic-gate 	    (new_acc == 0 && new_deny == 0))) {
19020Sstevel@tonic-gate 		/*
19030Sstevel@tonic-gate 		 * No downgrade to do, but still need to
19040Sstevel@tonic-gate 		 * update osp's os_share_* counts.
19050Sstevel@tonic-gate 		 */
19060Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_client_open_dg, (CE_NOTE,
19070Sstevel@tonic-gate 		    "nfs4_open_downgrade: just lower the osp's count by %s",
19080Sstevel@tonic-gate 		    (access_close & FREAD) && (access_close & FWRITE) ?
19090Sstevel@tonic-gate 		    "read and write" : (access_close & FREAD) ? "read" :
19100Sstevel@tonic-gate 		    (access_close & FWRITE) ? "write" : "bogus"));
19110Sstevel@tonic-gate 		if (access_close & FREAD)
19120Sstevel@tonic-gate 			osp->os_share_acc_read--;
19130Sstevel@tonic-gate 		if (access_close & FWRITE)
19140Sstevel@tonic-gate 			osp->os_share_acc_write--;
19150Sstevel@tonic-gate 		osp->os_share_deny_none--;
19160Sstevel@tonic-gate 		nfs4_error_zinit(ep);
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 		goto no_args_out;
19190Sstevel@tonic-gate 	}
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 	if (osp->os_orig_oo_name != oop->oo_name) {
19220Sstevel@tonic-gate 		ep->error = EIO;
19230Sstevel@tonic-gate 		goto no_args_out;
19240Sstevel@tonic-gate 	}
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 	/* setup the COMPOUND args */
19270Sstevel@tonic-gate 	if (lrp)
19280Sstevel@tonic-gate 		args.ctag = TAG_OPEN_DG_LOST;
19290Sstevel@tonic-gate 	else
19300Sstevel@tonic-gate 		args.ctag = TAG_OPEN_DG;
19310Sstevel@tonic-gate 
19320Sstevel@tonic-gate 	args.array_len = 3;
19330Sstevel@tonic-gate 	args.array = argop;
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 	/* putfh */
19360Sstevel@tonic-gate 	argop[0].argop = OP_CPUTFH;
19370Sstevel@tonic-gate 	argop[0].nfs_argop4_u.opcputfh.sfh = rp->r_fh;
19380Sstevel@tonic-gate 
19390Sstevel@tonic-gate 	argop[1].argop = OP_GETATTR;
19400Sstevel@tonic-gate 	argop[1].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
19410Sstevel@tonic-gate 	argop[1].nfs_argop4_u.opgetattr.mi = mi;
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	ASSERT(mutex_owned(&osp->os_sync_lock));
19440Sstevel@tonic-gate 	ASSERT(osp->os_delegation == FALSE);
19450Sstevel@tonic-gate 
19460Sstevel@tonic-gate 	/* open downgrade */
19470Sstevel@tonic-gate 	argop[2].argop = OP_OPEN_DOWNGRADE;
19480Sstevel@tonic-gate 	argop[2].nfs_argop4_u.opopen_downgrade.open_stateid = osp->open_stateid;
19490Sstevel@tonic-gate 	argop[2].nfs_argop4_u.opopen_downgrade.share_access = new_acc;
19500Sstevel@tonic-gate 	argop[2].nfs_argop4_u.opopen_downgrade.share_deny = new_deny;
19510Sstevel@tonic-gate 	argop[2].nfs_argop4_u.opopen_downgrade.seqid = seqid;
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate 	t = gethrtime();
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	rfs4call(mi, &args, &res, cred_otw, &doqueue, 0, ep);
19560Sstevel@tonic-gate 
19570Sstevel@tonic-gate 	if (ep->error == 0 && nfs4_need_to_bump_seqid(&res))
19580Sstevel@tonic-gate 		nfs4_set_open_seqid(seqid, oop, args.ctag);
19590Sstevel@tonic-gate 
19600Sstevel@tonic-gate 	if ((ep->error == EACCES ||
19610Sstevel@tonic-gate 	    (ep->error == 0 && res.status == NFS4ERR_ACCESS)) &&
19620Sstevel@tonic-gate 	    cred_otw != cr) {
19630Sstevel@tonic-gate 		crfree(cred_otw);
19640Sstevel@tonic-gate 		cred_otw = cr;
19650Sstevel@tonic-gate 		crhold(cred_otw);
19660Sstevel@tonic-gate 		if (!ep->error)
19670Sstevel@tonic-gate 			(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
19680Sstevel@tonic-gate 		goto cred_retry;
19690Sstevel@tonic-gate 	}
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	needrecov = nfs4_needs_recovery(ep, TRUE, mi->mi_vfsp);
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	if (needrecov && recov_credpp) {
19740Sstevel@tonic-gate 		*recov_credpp = cred_otw;
19750Sstevel@tonic-gate 		crhold(*recov_credpp);
19760Sstevel@tonic-gate 		if (recov_seqidp)
19770Sstevel@tonic-gate 			*recov_seqidp = seqid;
19780Sstevel@tonic-gate 	}
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 	if (!ep->error && !res.status) {
19810Sstevel@tonic-gate 		/* get the open downgrade results */
19820Sstevel@tonic-gate 		resop = &res.array[2];
19830Sstevel@tonic-gate 		odg_res = &resop->nfs_resop4_u.opopen_downgrade;
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate 		osp->open_stateid = odg_res->open_stateid;
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 		/* set the open streams new access/deny bits */
19880Sstevel@tonic-gate 		if (access_close & FREAD)
19890Sstevel@tonic-gate 			osp->os_share_acc_read--;
19900Sstevel@tonic-gate 		if (access_close & FWRITE)
19910Sstevel@tonic-gate 			osp->os_share_acc_write--;
19920Sstevel@tonic-gate 		osp->os_share_deny_none--;
19930Sstevel@tonic-gate 		osp->os_dc_openacc = new_acc;
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 		nfs4_attr_cache(vp,
19967902SNagakiran.Rajashekar@Sun.COM 		    &res.array[1].nfs_resop4_u.opgetattr.ga_res,
19977902SNagakiran.Rajashekar@Sun.COM 		    t, cred_otw, TRUE, NULL);
19980Sstevel@tonic-gate 	}
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 	if (!ep->error)
20010Sstevel@tonic-gate 		(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate no_args_out:
20040Sstevel@tonic-gate 	crfree(cred_otw);
20050Sstevel@tonic-gate }
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate /*
20080Sstevel@tonic-gate  * If an OPEN request gets ETIMEDOUT or EINTR (that includes bailing out
20090Sstevel@tonic-gate  * because the filesystem was forcibly unmounted) then we don't know if we
20100Sstevel@tonic-gate  * potentially left state dangling on the server, therefore the recovery
20110Sstevel@tonic-gate  * framework makes this call to resend the OPEN request and then undo it.
20120Sstevel@tonic-gate  */
20130Sstevel@tonic-gate void
nfs4_resend_open_otw(vnode_t ** vpp,nfs4_lost_rqst_t * resend_rqstp,nfs4_error_t * ep)20140Sstevel@tonic-gate nfs4_resend_open_otw(vnode_t **vpp, nfs4_lost_rqst_t *resend_rqstp,
20150Sstevel@tonic-gate 	nfs4_error_t *ep)
20160Sstevel@tonic-gate {
20170Sstevel@tonic-gate 	COMPOUND4args_clnt	args;
20180Sstevel@tonic-gate 	COMPOUND4res_clnt	res;
20190Sstevel@tonic-gate 	nfs_argop4		argop[4];
20200Sstevel@tonic-gate 	GETFH4res		*gf_res = NULL;
20210Sstevel@tonic-gate 	OPEN4cargs		*open_args;
20220Sstevel@tonic-gate 	OPEN4res		*op_res;
20230Sstevel@tonic-gate 	char			*destcfp;
20240Sstevel@tonic-gate 	int			destclen;
20250Sstevel@tonic-gate 	nfs4_ga_res_t		*garp;
20260Sstevel@tonic-gate 	vnode_t			*dvp = NULL, *vp = NULL;
20270Sstevel@tonic-gate 	rnode4_t		*rp = NULL, *drp = NULL;
20280Sstevel@tonic-gate 	cred_t			*cr = NULL;
20290Sstevel@tonic-gate 	seqid4			seqid;
20300Sstevel@tonic-gate 	nfs4_open_owner_t	*oop = NULL;
20310Sstevel@tonic-gate 	nfs4_open_stream_t	*osp = NULL;
20320Sstevel@tonic-gate 	component4		*srcfp;
20330Sstevel@tonic-gate 	open_claim_type4	claim;
20340Sstevel@tonic-gate 	mntinfo4_t		*mi;
20350Sstevel@tonic-gate 	int			doqueue = 1;
20360Sstevel@tonic-gate 	bool_t			retry_open = FALSE;
20370Sstevel@tonic-gate 	int			created_osp = 0;
20380Sstevel@tonic-gate 	hrtime_t		t;
20390Sstevel@tonic-gate 	char 			*failed_msg = "";
20400Sstevel@tonic-gate 	int			fh_different;
20413057Sjwahlig 	int			reopen = 0;
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 	nfs4_error_zinit(ep);
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 	cr = resend_rqstp->lr_cr;
20460Sstevel@tonic-gate 	dvp = resend_rqstp->lr_dvp;
20470Sstevel@tonic-gate 
20480Sstevel@tonic-gate 	vp = *vpp;
20490Sstevel@tonic-gate 	if (vp) {
20500Sstevel@tonic-gate 		ASSERT(nfs4_consistent_type(vp));
20510Sstevel@tonic-gate 		rp = VTOR4(vp);
20520Sstevel@tonic-gate 	}
20530Sstevel@tonic-gate 
20540Sstevel@tonic-gate 	if (rp) {
20550Sstevel@tonic-gate 		/* If the file failed recovery, just quit. */
20560Sstevel@tonic-gate 		mutex_enter(&rp->r_statelock);
20570Sstevel@tonic-gate 		if (rp->r_flags & R4RECOVERR) {
20580Sstevel@tonic-gate 			mutex_exit(&rp->r_statelock);
20590Sstevel@tonic-gate 			ep->error = EIO;
20600Sstevel@tonic-gate 			return;
20610Sstevel@tonic-gate 		}
20620Sstevel@tonic-gate 		mutex_exit(&rp->r_statelock);
20630Sstevel@tonic-gate 	}
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 	if (dvp) {
20660Sstevel@tonic-gate 		drp = VTOR4(dvp);
20670Sstevel@tonic-gate 		/* If the parent directory failed recovery, just quit. */
20680Sstevel@tonic-gate 		mutex_enter(&drp->r_statelock);
20690Sstevel@tonic-gate 		if (drp->r_flags & R4RECOVERR) {
20700Sstevel@tonic-gate 			mutex_exit(&drp->r_statelock);
20710Sstevel@tonic-gate 			ep->error = EIO;
20720Sstevel@tonic-gate 			return;
20730Sstevel@tonic-gate 		}
20740Sstevel@tonic-gate 		mutex_exit(&drp->r_statelock);
20753057Sjwahlig 	} else
20763057Sjwahlig 		reopen = 1;	/* NULL dvp means this is a reopen */
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 	claim = resend_rqstp->lr_oclaim;
20790Sstevel@tonic-gate 	ASSERT(claim == CLAIM_NULL || claim == CLAIM_DELEGATE_CUR);
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 	args.ctag = TAG_OPEN_LOST;
20820Sstevel@tonic-gate 	args.array_len = 4;
20830Sstevel@tonic-gate 	args.array = argop;
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 	argop[0].argop = OP_CPUTFH;
20863057Sjwahlig 	if (reopen) {
20870Sstevel@tonic-gate 		ASSERT(vp != NULL);
20880Sstevel@tonic-gate 
20890Sstevel@tonic-gate 		mi = VTOMI4(vp);
20900Sstevel@tonic-gate 		/*
20910Sstevel@tonic-gate 		 * if this is a file mount then
20920Sstevel@tonic-gate 		 * use the mntinfo parentfh
20930Sstevel@tonic-gate 		 */
20940Sstevel@tonic-gate 		argop[0].nfs_argop4_u.opcputfh.sfh =
20957902SNagakiran.Rajashekar@Sun.COM 		    (vp->v_flag & VROOT) ? mi->mi_srvparentfh :
20967902SNagakiran.Rajashekar@Sun.COM 		    VTOSV(vp)->sv_dfh;
20970Sstevel@tonic-gate 		args.ctag = TAG_REOPEN_LOST;
20980Sstevel@tonic-gate 	} else {
20990Sstevel@tonic-gate 		argop[0].nfs_argop4_u.opcputfh.sfh = VTOR4(dvp)->r_fh;
21000Sstevel@tonic-gate 		mi = VTOMI4(dvp);
21010Sstevel@tonic-gate 	}
21020Sstevel@tonic-gate 
21030Sstevel@tonic-gate 	argop[1].argop = OP_COPEN;
21040Sstevel@tonic-gate 	open_args = &argop[1].nfs_argop4_u.opcopen;
21050Sstevel@tonic-gate 	open_args->claim = claim;
21060Sstevel@tonic-gate 
21070Sstevel@tonic-gate 	/*
21080Sstevel@tonic-gate 	 * If we sent over a OPEN with CREATE then the only
21090Sstevel@tonic-gate 	 * thing we care about is to not leave dangling state
21100Sstevel@tonic-gate 	 * on the server, not whether the file we potentially
21110Sstevel@tonic-gate 	 * created remains on the server.  So even though the
21120Sstevel@tonic-gate 	 * lost open request specified a CREATE, we only wish
21130Sstevel@tonic-gate 	 * to do a non-CREATE OPEN.
21140Sstevel@tonic-gate 	 */
21150Sstevel@tonic-gate 	open_args->opentype = OPEN4_NOCREATE;
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 	srcfp = &resend_rqstp->lr_ofile;
21180Sstevel@tonic-gate 	destclen = srcfp->utf8string_len;
21190Sstevel@tonic-gate 	destcfp = kmem_alloc(destclen + 1, KM_SLEEP);
21200Sstevel@tonic-gate 	bcopy(srcfp->utf8string_val, destcfp, destclen);
21210Sstevel@tonic-gate 	destcfp[destclen] = '\0';
21220Sstevel@tonic-gate 	if (claim == CLAIM_DELEGATE_CUR) {
21230Sstevel@tonic-gate 		open_args->open_claim4_u.delegate_cur_info.delegate_stateid =
21247902SNagakiran.Rajashekar@Sun.COM 		    resend_rqstp->lr_ostateid;
21250Sstevel@tonic-gate 		open_args->open_claim4_u.delegate_cur_info.cfile = destcfp;
21260Sstevel@tonic-gate 	} else {
21270Sstevel@tonic-gate 		open_args->open_claim4_u.cfile = destcfp;
21280Sstevel@tonic-gate 	}
21290Sstevel@tonic-gate 
21300Sstevel@tonic-gate 	open_args->share_access = resend_rqstp->lr_oacc;
21310Sstevel@tonic-gate 	open_args->share_deny = resend_rqstp->lr_odeny;
21320Sstevel@tonic-gate 	oop = resend_rqstp->lr_oop;
21330Sstevel@tonic-gate 	ASSERT(oop != NULL);
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 	open_args->owner.clientid = mi2clientid(mi);
21360Sstevel@tonic-gate 	/* this length never changes */
21370Sstevel@tonic-gate 	open_args->owner.owner_len = sizeof (oop->oo_name);
21380Sstevel@tonic-gate 	open_args->owner.owner_val =
21390Sstevel@tonic-gate 	    kmem_alloc(open_args->owner.owner_len, KM_SLEEP);
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 	ep->error = nfs4_start_open_seqid_sync(oop, mi);
21420Sstevel@tonic-gate 	ASSERT(ep->error == 0);		/* recov thread always succeeds */
21430Sstevel@tonic-gate 	/*
21440Sstevel@tonic-gate 	 * We can get away with not saving the seqid upon detection
21450Sstevel@tonic-gate 	 * of a lost request, and now just use the open owner's current
21460Sstevel@tonic-gate 	 * seqid since we only allow one op OTW per seqid and lost
21470Sstevel@tonic-gate 	 * requests are saved FIFO.
21480Sstevel@tonic-gate 	 */
21490Sstevel@tonic-gate 	seqid = nfs4_get_open_seqid(oop) + 1;
21500Sstevel@tonic-gate 	open_args->seqid = seqid;
21510Sstevel@tonic-gate 
21520Sstevel@tonic-gate 	bcopy(&oop->oo_name, open_args->owner.owner_val,
21530Sstevel@tonic-gate 	    open_args->owner.owner_len);
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate 	/* getfh */
21560Sstevel@tonic-gate 	argop[2].argop = OP_GETFH;
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 	/* Construct the getattr part of the compound */
21590Sstevel@tonic-gate 	argop[3].argop = OP_GETATTR;
21600Sstevel@tonic-gate 	argop[3].nfs_argop4_u.opgetattr.attr_request = NFS4_VATTR_MASK;
21610Sstevel@tonic-gate 	argop[3].nfs_argop4_u.opgetattr.mi = mi;
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	res.array = NULL;
21640Sstevel@tonic-gate 
21650Sstevel@tonic-gate 	t = gethrtime();
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	rfs4call(mi, &args, &res, cr, &doqueue, 0, ep);
21680Sstevel@tonic-gate 
21690Sstevel@tonic-gate 	if (ep->error == 0 && nfs4_need_to_bump_seqid(&res))
21700Sstevel@tonic-gate 		nfs4_set_open_seqid(seqid, oop, args.ctag);
21710Sstevel@tonic-gate 
21720Sstevel@tonic-gate 	NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
21730Sstevel@tonic-gate 	    "nfs4_resend_open_otw: error %d stat %d", ep->error, res.status));
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 	if (ep->error || res.status)
21760Sstevel@tonic-gate 		goto err_out;
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 	op_res = &res.array[1].nfs_resop4_u.opopen;
21790Sstevel@tonic-gate 	gf_res = &res.array[2].nfs_resop4_u.opgetfh;
21800Sstevel@tonic-gate 	garp = &res.array[3].nfs_resop4_u.opgetattr.ga_res;
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate 	if (!vp) {
21830Sstevel@tonic-gate 		int rnode_err = 0;
21840Sstevel@tonic-gate 		nfs4_sharedfh_t *sfh;
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate 		/*
21870Sstevel@tonic-gate 		 * If we can't decode all the attributes they are not usable,
21880Sstevel@tonic-gate 		 * just make the vnode.
21890Sstevel@tonic-gate 		 */
21900Sstevel@tonic-gate 
21910Sstevel@tonic-gate 		sfh = sfh4_get(&gf_res->object, VTOMI4(dvp));
21920Sstevel@tonic-gate 		*vpp = makenfs4node(sfh, garp, dvp->v_vfsp, t, cr, dvp,
21937902SNagakiran.Rajashekar@Sun.COM 		    fn_get(VTOSV(dvp)->sv_name,
21947902SNagakiran.Rajashekar@Sun.COM 		    open_args->open_claim4_u.cfile, sfh));
21950Sstevel@tonic-gate 		sfh4_rele(&sfh);
21960Sstevel@tonic-gate 		NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
21970Sstevel@tonic-gate 		    "nfs4_resend_open_otw: made vp %p for file %s",
21980Sstevel@tonic-gate 		    (void *)(*vpp), open_args->open_claim4_u.cfile));
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 		if (ep->error)
22010Sstevel@tonic-gate 			PURGE_ATTRCACHE4(*vpp);
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 		/*
22040Sstevel@tonic-gate 		 * For the newly created *vpp case, make sure the rnode
22050Sstevel@tonic-gate 		 * isn't bad before using it.
22060Sstevel@tonic-gate 		 */
22070Sstevel@tonic-gate 		mutex_enter(&(VTOR4(*vpp))->r_statelock);
22080Sstevel@tonic-gate 		if (VTOR4(*vpp)->r_flags & R4RECOVERR)
22090Sstevel@tonic-gate 			rnode_err = EIO;
22100Sstevel@tonic-gate 		mutex_exit(&(VTOR4(*vpp))->r_statelock);
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate 		if (rnode_err) {
22130Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
22140Sstevel@tonic-gate 			    "nfs4_resend_open_otw: rp %p is bad",
22150Sstevel@tonic-gate 			    (void *)VTOR4(*vpp)));
22160Sstevel@tonic-gate 			ep->error = rnode_err;
22170Sstevel@tonic-gate 			goto err_out;
22180Sstevel@tonic-gate 		}
22190Sstevel@tonic-gate 
22200Sstevel@tonic-gate 		vp = *vpp;
22210Sstevel@tonic-gate 		rp = VTOR4(vp);
22220Sstevel@tonic-gate 	}
22230Sstevel@tonic-gate 
22243057Sjwahlig 	if (reopen) {
22250Sstevel@tonic-gate 		/*
22260Sstevel@tonic-gate 		 * Check if the path we reopened really is the same
22270Sstevel@tonic-gate 		 * file. We could end up in a situation were the file
22280Sstevel@tonic-gate 		 * was removed and a new file created with the same name.
22290Sstevel@tonic-gate 		 */
22300Sstevel@tonic-gate 		(void) nfs_rw_enter_sig(&mi->mi_fh_lock, RW_READER, 0);
22310Sstevel@tonic-gate 		fh_different =
22327902SNagakiran.Rajashekar@Sun.COM 		    (nfs4cmpfh(&rp->r_fh->sfh_fh, &gf_res->object) != 0);
22330Sstevel@tonic-gate 		if (fh_different) {
22340Sstevel@tonic-gate 			if (mi->mi_fh_expire_type == FH4_PERSISTENT ||
22350Sstevel@tonic-gate 			    mi->mi_fh_expire_type & FH4_NOEXPIRE_WITH_OPEN) {
22360Sstevel@tonic-gate 				/* Oops, we don't have the same file */
22370Sstevel@tonic-gate 				if (mi->mi_fh_expire_type == FH4_PERSISTENT)
22380Sstevel@tonic-gate 					failed_msg =
22390Sstevel@tonic-gate 					    "Couldn't reopen: Persistant "
22400Sstevel@tonic-gate 					    "file handle changed";
22410Sstevel@tonic-gate 				else
22420Sstevel@tonic-gate 					failed_msg =
22430Sstevel@tonic-gate 					    "Couldn't reopen: Volatile "
22440Sstevel@tonic-gate 					    "(no expire on open) file handle "
22450Sstevel@tonic-gate 					    "changed";
22460Sstevel@tonic-gate 
22470Sstevel@tonic-gate 				nfs4_end_open_seqid_sync(oop);
22480Sstevel@tonic-gate 				kmem_free(destcfp, destclen + 1);
22490Sstevel@tonic-gate 				nfs4args_copen_free(open_args);
22500Sstevel@tonic-gate 				(void) xdr_free(xdr_COMPOUND4res_clnt,
22517902SNagakiran.Rajashekar@Sun.COM 				    (caddr_t)&res);
22520Sstevel@tonic-gate 				nfs_rw_exit(&mi->mi_fh_lock);
22530Sstevel@tonic-gate 				nfs4_fail_recov(vp, failed_msg, ep->error,
22547902SNagakiran.Rajashekar@Sun.COM 				    ep->stat);
22550Sstevel@tonic-gate 				return;
22560Sstevel@tonic-gate 			} else {
22570Sstevel@tonic-gate 				/*
22580Sstevel@tonic-gate 				 * We have volatile file handles that don't
22590Sstevel@tonic-gate 				 * compare.  If the fids are the same then we
22600Sstevel@tonic-gate 				 * assume that the file handle expired but the
22610Sstevel@tonic-gate 				 * renode still refers to the same file object.
22620Sstevel@tonic-gate 				 *
22630Sstevel@tonic-gate 				 * First check that we have fids or not.
22640Sstevel@tonic-gate 				 * If we don't we have a dumb server so we will
22650Sstevel@tonic-gate 				 * just assume every thing is ok for now.
22660Sstevel@tonic-gate 				 */
22670Sstevel@tonic-gate 				if (!ep->error &&
22680Sstevel@tonic-gate 				    garp->n4g_va.va_mask & AT_NODEID &&
22690Sstevel@tonic-gate 				    rp->r_attr.va_mask & AT_NODEID &&
22700Sstevel@tonic-gate 				    rp->r_attr.va_nodeid !=
22717902SNagakiran.Rajashekar@Sun.COM 				    garp->n4g_va.va_nodeid) {
22720Sstevel@tonic-gate 					/*
22730Sstevel@tonic-gate 					 * We have fids, but they don't
22740Sstevel@tonic-gate 					 * compare. So kill the file.
22750Sstevel@tonic-gate 					 */
22760Sstevel@tonic-gate 					failed_msg =
22770Sstevel@tonic-gate 					    "Couldn't reopen: file handle "
22780Sstevel@tonic-gate 					    "changed due to mismatched fids";
22790Sstevel@tonic-gate 					nfs4_end_open_seqid_sync(oop);
22800Sstevel@tonic-gate 					kmem_free(destcfp, destclen + 1);
22810Sstevel@tonic-gate 					nfs4args_copen_free(open_args);
22820Sstevel@tonic-gate 					(void) xdr_free(xdr_COMPOUND4res_clnt,
22837902SNagakiran.Rajashekar@Sun.COM 					    (caddr_t)&res);
22840Sstevel@tonic-gate 					nfs_rw_exit(&mi->mi_fh_lock);
22850Sstevel@tonic-gate 					nfs4_fail_recov(vp, failed_msg,
22867902SNagakiran.Rajashekar@Sun.COM 					    ep->error, ep->stat);
22870Sstevel@tonic-gate 					return;
22880Sstevel@tonic-gate 				} else {
22890Sstevel@tonic-gate 					/*
22900Sstevel@tonic-gate 					 * We have volatile file handles that
22910Sstevel@tonic-gate 					 * refers to the same file (at least
22920Sstevel@tonic-gate 					 * they have the same fid) or we don't
22930Sstevel@tonic-gate 					 * have fids so we can't tell. :(. We'll
22940Sstevel@tonic-gate 					 * be a kind and accepting client so
22950Sstevel@tonic-gate 					 * we'll update the rnode's file
22960Sstevel@tonic-gate 					 * handle with the otw handle.
22970Sstevel@tonic-gate 					 *
22980Sstevel@tonic-gate 					 * We need to drop mi->mi_fh_lock since
22990Sstevel@tonic-gate 					 * sh4_update acquires it. Since there
23000Sstevel@tonic-gate 					 * is only one recovery thread there is
23010Sstevel@tonic-gate 					 * no race.
23020Sstevel@tonic-gate 					 */
23030Sstevel@tonic-gate 					nfs_rw_exit(&mi->mi_fh_lock);
23040Sstevel@tonic-gate 					sfh4_update(rp->r_fh, &gf_res->object);
23050Sstevel@tonic-gate 				}
23060Sstevel@tonic-gate 			}
23070Sstevel@tonic-gate 		} else {
23080Sstevel@tonic-gate 			nfs_rw_exit(&mi->mi_fh_lock);
23090Sstevel@tonic-gate 		}
23100Sstevel@tonic-gate 	}
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 	ASSERT(nfs4_consistent_type(vp));
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate 	if (op_res->rflags & OPEN4_RESULT_CONFIRM)
23150Sstevel@tonic-gate 		nfs4open_confirm(vp, &seqid, &op_res->stateid, cr, TRUE,
23160Sstevel@tonic-gate 		    &retry_open, oop, TRUE, ep, NULL);
23170Sstevel@tonic-gate 	if (ep->error || ep->stat) {
23180Sstevel@tonic-gate 		nfs4_end_open_seqid_sync(oop);
23190Sstevel@tonic-gate 		kmem_free(destcfp, destclen + 1);
23200Sstevel@tonic-gate 		nfs4args_copen_free(open_args);
23210Sstevel@tonic-gate 		if (!ep->error)
23220Sstevel@tonic-gate 			(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
23230Sstevel@tonic-gate 		return;
23240Sstevel@tonic-gate 	}
23250Sstevel@tonic-gate 
23263057Sjwahlig 	if (reopen) {
23270Sstevel@tonic-gate 		/*
23280Sstevel@tonic-gate 		 * Doing a reopen here so the osp should already exist.
23290Sstevel@tonic-gate 		 * If not, something changed or went very wrong.
23300Sstevel@tonic-gate 		 *
23310Sstevel@tonic-gate 		 * returns with 'os_sync_lock' held
23320Sstevel@tonic-gate 		 */
23330Sstevel@tonic-gate 		osp = find_open_stream(oop, rp);
23340Sstevel@tonic-gate 		if (!osp) {
23350Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
23360Sstevel@tonic-gate 			    "nfs4_resend_open_otw: couldn't find osp"));
23370Sstevel@tonic-gate 			ep->error = EINVAL;
23380Sstevel@tonic-gate 			goto err_out;
23390Sstevel@tonic-gate 		}
23400Sstevel@tonic-gate 		osp->os_open_ref_count++;
23410Sstevel@tonic-gate 	} else {
23420Sstevel@tonic-gate 		mutex_enter(&oop->oo_lock);
23430Sstevel@tonic-gate 		oop->oo_just_created = NFS4_PERM_CREATED;
23440Sstevel@tonic-gate 		mutex_exit(&oop->oo_lock);
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 		/* returns with 'os_sync_lock' held */
23470Sstevel@tonic-gate 		osp = find_or_create_open_stream(oop, rp, &created_osp);
23480Sstevel@tonic-gate 		if (!osp) {
23490Sstevel@tonic-gate 			NFS4_DEBUG(nfs4_lost_rqst_debug, (CE_NOTE,
23500Sstevel@tonic-gate 			    "nfs4_resend_open_otw: couldn't create osp"));
23510Sstevel@tonic-gate 			ep->error = EINVAL;
23520Sstevel@tonic-gate 			goto err_out;
23530Sstevel@tonic-gate 		}
23540Sstevel@tonic-gate 	}
23550Sstevel@tonic-gate 
23560Sstevel@tonic-gate 	osp->open_stateid = op_res->stateid;
23570Sstevel@tonic-gate 	osp->os_delegation = FALSE;
23580Sstevel@tonic-gate 	/*
23590Sstevel@tonic-gate 	 * Need to reset this bitfield for the possible case where we were
23600Sstevel@tonic-gate 	 * going to OTW CLOSE the file, got a non-recoverable error, and before
23610Sstevel@tonic-gate 	 * we could retry the CLOSE, OPENed the file again.
23620Sstevel@tonic-gate 	 */
23630Sstevel@tonic-gate 	ASSERT(osp->os_open_owner->oo_seqid_inuse);
23640Sstevel@tonic-gate 	osp->os_final_close = 0;
23650Sstevel@tonic-gate 	osp->os_force_close = 0;
23660Sstevel@tonic-gate 
23673057Sjwahlig 	if (!reopen) {
23680Sstevel@tonic-gate 		if (open_args->share_access & OPEN4_SHARE_ACCESS_READ)
23690Sstevel@tonic-gate 			osp->os_share_acc_read++;
23700Sstevel@tonic-gate 		if (open_args->share_access & OPEN4_SHARE_ACCESS_WRITE)
23710Sstevel@tonic-gate 			osp->os_share_acc_write++;
23720Sstevel@tonic-gate 		osp->os_share_deny_none++;
23730Sstevel@tonic-gate 	}
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate 	mutex_exit(&osp->os_sync_lock);
23760Sstevel@tonic-gate 	if (created_osp)
23770Sstevel@tonic-gate 		nfs4_inc_state_ref_count(mi);
23780Sstevel@tonic-gate 	open_stream_rele(osp, rp);
23790Sstevel@tonic-gate 
23800Sstevel@tonic-gate 	nfs4_end_open_seqid_sync(oop);
23810Sstevel@tonic-gate 
23820Sstevel@tonic-gate 	/* accept delegation, if any */
23830Sstevel@tonic-gate 	nfs4_delegation_accept(rp, claim, op_res, garp, cr);
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	kmem_free(destcfp, destclen + 1);
23860Sstevel@tonic-gate 	nfs4args_copen_free(open_args);
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 	if (claim == CLAIM_DELEGATE_CUR)
23890Sstevel@tonic-gate 		nfs4_attr_cache(vp, garp, t, cr, TRUE, NULL);
23900Sstevel@tonic-gate 	else
23910Sstevel@tonic-gate 		PURGE_ATTRCACHE4(vp);
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 	ASSERT(nfs4_consistent_type(vp));
23960Sstevel@tonic-gate 
23970Sstevel@tonic-gate 	return;
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate err_out:
24000Sstevel@tonic-gate 	nfs4_end_open_seqid_sync(oop);
24010Sstevel@tonic-gate 	kmem_free(destcfp, destclen + 1);
24020Sstevel@tonic-gate 	nfs4args_copen_free(open_args);
24030Sstevel@tonic-gate 	if (!ep->error)
24040Sstevel@tonic-gate 		(void) xdr_free(xdr_COMPOUND4res_clnt, (caddr_t)&res);
24050Sstevel@tonic-gate }
2406