xref: /illumos-gate/usr/src/uts/common/fs/lofs/lofs_subr.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * The idea behind composition-based stacked filesystems is to add a
31*7c478bd9Sstevel@tonic-gate  * vnode to the stack of vnodes for each mount. These vnodes have their
32*7c478bd9Sstevel@tonic-gate  * own set of mount options and filesystem-specific functions, so they
33*7c478bd9Sstevel@tonic-gate  * can modify data or operations before they are passed along. Such a
34*7c478bd9Sstevel@tonic-gate  * filesystem must maintain a mapping from the underlying vnodes to its
35*7c478bd9Sstevel@tonic-gate  * interposing vnodes.
36*7c478bd9Sstevel@tonic-gate  *
37*7c478bd9Sstevel@tonic-gate  * In lofs, this mapping is implemented by a hashtable. Each bucket
38*7c478bd9Sstevel@tonic-gate  * contains a count of the number of nodes currently contained, the
39*7c478bd9Sstevel@tonic-gate  * chain of vnodes, and a lock to protect the list of vnodes. The
40*7c478bd9Sstevel@tonic-gate  * hashtable dynamically grows if the number of vnodes in the table as a
41*7c478bd9Sstevel@tonic-gate  * whole exceeds the size of the table left-shifted by
42*7c478bd9Sstevel@tonic-gate  * lo_resize_threshold. In order to minimize lock contention, there is
43*7c478bd9Sstevel@tonic-gate  * no global lock protecting the hashtable, hence obtaining the
44*7c478bd9Sstevel@tonic-gate  * per-bucket locks consists of a dance to make sure we've actually
45*7c478bd9Sstevel@tonic-gate  * locked the correct bucket. Acquiring a bucket lock doesn't involve
46*7c478bd9Sstevel@tonic-gate  * locking the hashtable itself, so we refrain from freeing old
47*7c478bd9Sstevel@tonic-gate  * hashtables, and store them in a linked list of retired hashtables;
48*7c478bd9Sstevel@tonic-gate  * the list is freed when the filesystem is unmounted.
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate #include <sys/fs/lofs_node.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/fs/lofs_info.h>
63*7c478bd9Sstevel@tonic-gate /*
64*7c478bd9Sstevel@tonic-gate  * Due to the hashing algorithm, the size of the hash table needs to be a
65*7c478bd9Sstevel@tonic-gate  * power of 2.
66*7c478bd9Sstevel@tonic-gate  */
67*7c478bd9Sstevel@tonic-gate #define	LOFS_DEFAULT_HTSIZE	(1 << 6)
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate #define	ltablehash(vp, tblsz)	((((intptr_t)(vp))>>10) & ((tblsz)-1))
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * The following macros can only be safely used when the desired bucket
73*7c478bd9Sstevel@tonic-gate  * is already locked.
74*7c478bd9Sstevel@tonic-gate  */
75*7c478bd9Sstevel@tonic-gate /*
76*7c478bd9Sstevel@tonic-gate  * The lock in the hashtable associated with the given vnode.
77*7c478bd9Sstevel@tonic-gate  */
78*7c478bd9Sstevel@tonic-gate #define	TABLE_LOCK(vp, li)      \
79*7c478bd9Sstevel@tonic-gate 	(&(li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_lock)
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /*
82*7c478bd9Sstevel@tonic-gate  * The bucket in the hashtable that the given vnode hashes to.
83*7c478bd9Sstevel@tonic-gate  */
84*7c478bd9Sstevel@tonic-gate #define	TABLE_BUCKET(vp, li)    \
85*7c478bd9Sstevel@tonic-gate 	((li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_chain)
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate /*
88*7c478bd9Sstevel@tonic-gate  * Number of elements currently in the bucket that the vnode hashes to.
89*7c478bd9Sstevel@tonic-gate  */
90*7c478bd9Sstevel@tonic-gate #define	TABLE_COUNT(vp, li)	\
91*7c478bd9Sstevel@tonic-gate 	((li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_count)
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate /*
94*7c478bd9Sstevel@tonic-gate  * Grab/Drop the lock for the bucket this vnode hashes to.
95*7c478bd9Sstevel@tonic-gate  */
96*7c478bd9Sstevel@tonic-gate #define	TABLE_LOCK_ENTER(vp, li)	table_lock_enter(vp, li)
97*7c478bd9Sstevel@tonic-gate #define	TABLE_LOCK_EXIT(vp, li)		\
98*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(li)->li_hashtable[ltablehash((vp),	\
99*7c478bd9Sstevel@tonic-gate 	    (li)->li_htsize)].lh_lock)
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate static lnode_t *lfind(struct vnode *, struct loinfo *);
102*7c478bd9Sstevel@tonic-gate static void lsave(lnode_t *, struct loinfo *);
103*7c478bd9Sstevel@tonic-gate static struct vfs *makelfsnode(struct vfs *, struct loinfo *);
104*7c478bd9Sstevel@tonic-gate static struct lfsnode *lfsfind(struct vfs *, struct loinfo *);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate uint_t lo_resize_threshold = 1;
107*7c478bd9Sstevel@tonic-gate uint_t lo_resize_factor = 2;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static kmem_cache_t *lnode_cache;
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate /*
112*7c478bd9Sstevel@tonic-gate  * Since the hashtable itself isn't protected by a lock, obtaining a
113*7c478bd9Sstevel@tonic-gate  * per-bucket lock proceeds as follows:
114*7c478bd9Sstevel@tonic-gate  *
115*7c478bd9Sstevel@tonic-gate  * (a) li->li_htlock protects li->li_hashtable, li->li_htsize, and
116*7c478bd9Sstevel@tonic-gate  * li->li_retired.
117*7c478bd9Sstevel@tonic-gate  *
118*7c478bd9Sstevel@tonic-gate  * (b) Per-bucket locks (lh_lock) protect the contents of the bucket.
119*7c478bd9Sstevel@tonic-gate  *
120*7c478bd9Sstevel@tonic-gate  * (c) Locking order for resizing the hashtable is li_htlock then
121*7c478bd9Sstevel@tonic-gate  * lh_lock.
122*7c478bd9Sstevel@tonic-gate  *
123*7c478bd9Sstevel@tonic-gate  * To grab the bucket lock we:
124*7c478bd9Sstevel@tonic-gate  *
125*7c478bd9Sstevel@tonic-gate  * (1) Stash away the htsize and the pointer to the hashtable to make
126*7c478bd9Sstevel@tonic-gate  * sure neither change while we're using them.
127*7c478bd9Sstevel@tonic-gate  *
128*7c478bd9Sstevel@tonic-gate  * (2) lgrow() updates the pointer to the hashtable before it updates
129*7c478bd9Sstevel@tonic-gate  * the size: the worst case scenario is that we have the wrong size (but
130*7c478bd9Sstevel@tonic-gate  * the correct table), so we hash to the wrong bucket, grab the wrong
131*7c478bd9Sstevel@tonic-gate  * lock, and then realize that things have changed, rewind and start
132*7c478bd9Sstevel@tonic-gate  * again. If both the size and the table changed since we loaded them,
133*7c478bd9Sstevel@tonic-gate  * we'll realize that too and restart.
134*7c478bd9Sstevel@tonic-gate  *
135*7c478bd9Sstevel@tonic-gate  * (3) The protocol for growing the hashtable involves holding *all* the
136*7c478bd9Sstevel@tonic-gate  * locks in the table, hence the unlocking code (TABLE_LOCK_EXIT())
137*7c478bd9Sstevel@tonic-gate  * doesn't need to do any dances, since neither the table nor the size
138*7c478bd9Sstevel@tonic-gate  * can change while any bucket lock is held.
139*7c478bd9Sstevel@tonic-gate  *
140*7c478bd9Sstevel@tonic-gate  * (4) If the hashtable is growing (by thread t1) while another thread
141*7c478bd9Sstevel@tonic-gate  * (t2) is trying to grab a bucket lock, t2 might have a stale reference
142*7c478bd9Sstevel@tonic-gate  * to li->li_htsize:
143*7c478bd9Sstevel@tonic-gate  *
144*7c478bd9Sstevel@tonic-gate  * - t1 grabs all locks in lgrow()
145*7c478bd9Sstevel@tonic-gate  * 	- t2 loads li->li_htsize and li->li_hashtable
146*7c478bd9Sstevel@tonic-gate  * - t1 changes li->hashtable
147*7c478bd9Sstevel@tonic-gate  * 	- t2 loads from an offset in the "stale" hashtable and tries to grab
148*7c478bd9Sstevel@tonic-gate  * 	the relevant mutex.
149*7c478bd9Sstevel@tonic-gate  *
150*7c478bd9Sstevel@tonic-gate  * If t1 had free'd the stale hashtable, t2 would be in trouble. Hence,
151*7c478bd9Sstevel@tonic-gate  * stale hashtables are not freed but stored in a list of "retired"
152*7c478bd9Sstevel@tonic-gate  * hashtables, which is emptied when the filesystem is unmounted.
153*7c478bd9Sstevel@tonic-gate  */
154*7c478bd9Sstevel@tonic-gate static void
155*7c478bd9Sstevel@tonic-gate table_lock_enter(vnode_t *vp, struct loinfo *li)
156*7c478bd9Sstevel@tonic-gate {
157*7c478bd9Sstevel@tonic-gate 	struct lobucket *chain;
158*7c478bd9Sstevel@tonic-gate 	uint_t htsize;
159*7c478bd9Sstevel@tonic-gate 	uint_t hash;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	for (;;) {
162*7c478bd9Sstevel@tonic-gate 		htsize = li->li_htsize;
163*7c478bd9Sstevel@tonic-gate 		membar_consumer();
164*7c478bd9Sstevel@tonic-gate 		chain = (struct lobucket *)li->li_hashtable;
165*7c478bd9Sstevel@tonic-gate 		hash = ltablehash(vp, htsize);
166*7c478bd9Sstevel@tonic-gate 		mutex_enter(&chain[hash].lh_lock);
167*7c478bd9Sstevel@tonic-gate 		if (li->li_hashtable == chain && li->li_htsize == htsize)
168*7c478bd9Sstevel@tonic-gate 			break;
169*7c478bd9Sstevel@tonic-gate 		mutex_exit(&chain[hash].lh_lock);
170*7c478bd9Sstevel@tonic-gate 	}
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate void
174*7c478bd9Sstevel@tonic-gate lofs_subrinit(void)
175*7c478bd9Sstevel@tonic-gate {
176*7c478bd9Sstevel@tonic-gate 	/*
177*7c478bd9Sstevel@tonic-gate 	 * Initialize the cache.
178*7c478bd9Sstevel@tonic-gate 	 */
179*7c478bd9Sstevel@tonic-gate 	lnode_cache = kmem_cache_create("lnode_cache", sizeof (lnode_t),
180*7c478bd9Sstevel@tonic-gate 	    0, NULL, NULL, NULL, NULL, NULL, 0);
181*7c478bd9Sstevel@tonic-gate }
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate void
184*7c478bd9Sstevel@tonic-gate lofs_subrfini(void)
185*7c478bd9Sstevel@tonic-gate {
186*7c478bd9Sstevel@tonic-gate 	kmem_cache_destroy(lnode_cache);
187*7c478bd9Sstevel@tonic-gate }
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate /*
190*7c478bd9Sstevel@tonic-gate  * Initialize a (struct loinfo), and initialize the hashtable to have
191*7c478bd9Sstevel@tonic-gate  * htsize buckets.
192*7c478bd9Sstevel@tonic-gate  */
193*7c478bd9Sstevel@tonic-gate void
194*7c478bd9Sstevel@tonic-gate lsetup(struct loinfo *li, uint_t htsize)
195*7c478bd9Sstevel@tonic-gate {
196*7c478bd9Sstevel@tonic-gate 	li->li_refct = 0;
197*7c478bd9Sstevel@tonic-gate 	li->li_lfs = NULL;
198*7c478bd9Sstevel@tonic-gate 	if (htsize == 0)
199*7c478bd9Sstevel@tonic-gate 		htsize = LOFS_DEFAULT_HTSIZE;
200*7c478bd9Sstevel@tonic-gate 	li->li_htsize = htsize;
201*7c478bd9Sstevel@tonic-gate 	li->li_hashtable = kmem_zalloc(htsize * sizeof (*li->li_hashtable),
202*7c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
203*7c478bd9Sstevel@tonic-gate 	mutex_init(&li->li_lfslock, NULL, MUTEX_DEFAULT, NULL);
204*7c478bd9Sstevel@tonic-gate 	mutex_init(&li->li_htlock, NULL, MUTEX_DEFAULT, NULL);
205*7c478bd9Sstevel@tonic-gate 	li->li_retired = NULL;
206*7c478bd9Sstevel@tonic-gate }
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate /*
209*7c478bd9Sstevel@tonic-gate  * Destroy a (struct loinfo)
210*7c478bd9Sstevel@tonic-gate  */
211*7c478bd9Sstevel@tonic-gate void
212*7c478bd9Sstevel@tonic-gate ldestroy(struct loinfo *li)
213*7c478bd9Sstevel@tonic-gate {
214*7c478bd9Sstevel@tonic-gate 	uint_t i, htsize;
215*7c478bd9Sstevel@tonic-gate 	struct lobucket *table;
216*7c478bd9Sstevel@tonic-gate 	struct lo_retired_ht *lrhp, *trhp;
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&li->li_htlock);
219*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&li->li_lfslock);
220*7c478bd9Sstevel@tonic-gate 	htsize = li->li_htsize;
221*7c478bd9Sstevel@tonic-gate 	table = li->li_hashtable;
222*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < htsize; i++)
223*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&table[i].lh_lock);
224*7c478bd9Sstevel@tonic-gate 	kmem_free(table, htsize * sizeof (*li->li_hashtable));
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate 	/*
227*7c478bd9Sstevel@tonic-gate 	 * Free the retired hashtables.
228*7c478bd9Sstevel@tonic-gate 	 */
229*7c478bd9Sstevel@tonic-gate 	lrhp = li->li_retired;
230*7c478bd9Sstevel@tonic-gate 	while (lrhp != NULL) {
231*7c478bd9Sstevel@tonic-gate 		trhp = lrhp;
232*7c478bd9Sstevel@tonic-gate 		lrhp = lrhp->lrh_next;
233*7c478bd9Sstevel@tonic-gate 		kmem_free(trhp->lrh_table,
234*7c478bd9Sstevel@tonic-gate 		    trhp->lrh_size * sizeof (*li->li_hashtable));
235*7c478bd9Sstevel@tonic-gate 		kmem_free(trhp, sizeof (*trhp));
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 	li->li_retired = NULL;
238*7c478bd9Sstevel@tonic-gate }
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate /*
241*7c478bd9Sstevel@tonic-gate  * Return a looped back vnode for the given vnode.
242*7c478bd9Sstevel@tonic-gate  * If no lnode exists for this vnode create one and put it
243*7c478bd9Sstevel@tonic-gate  * in a table hashed by vnode.  If the lnode for
244*7c478bd9Sstevel@tonic-gate  * this vnode is already in the table return it (ref count is
245*7c478bd9Sstevel@tonic-gate  * incremented by lfind).  The lnode will be flushed from the
246*7c478bd9Sstevel@tonic-gate  * table when lo_inactive calls freelonode.
247*7c478bd9Sstevel@tonic-gate  * NOTE: vp is assumed to be a held vnode.
248*7c478bd9Sstevel@tonic-gate  */
249*7c478bd9Sstevel@tonic-gate struct vnode *
250*7c478bd9Sstevel@tonic-gate makelonode(struct vnode *vp, struct loinfo *li)
251*7c478bd9Sstevel@tonic-gate {
252*7c478bd9Sstevel@tonic-gate 	lnode_t *lp, *tlp;
253*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
254*7c478bd9Sstevel@tonic-gate 	vnode_t *nvp;
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	TABLE_LOCK_ENTER(vp, li);
257*7c478bd9Sstevel@tonic-gate 	if ((lp = lfind(vp, li)) == NULL) {
258*7c478bd9Sstevel@tonic-gate 		/*
259*7c478bd9Sstevel@tonic-gate 		 * Optimistically assume that we won't need to sleep.
260*7c478bd9Sstevel@tonic-gate 		 */
261*7c478bd9Sstevel@tonic-gate 		lp = kmem_cache_alloc(lnode_cache, KM_NOSLEEP);
262*7c478bd9Sstevel@tonic-gate 		nvp = vn_alloc(KM_NOSLEEP);
263*7c478bd9Sstevel@tonic-gate 		if (lp == NULL || nvp == NULL) {
264*7c478bd9Sstevel@tonic-gate 			TABLE_LOCK_EXIT(vp, li);
265*7c478bd9Sstevel@tonic-gate 			/* The lnode allocation may have succeeded, save it */
266*7c478bd9Sstevel@tonic-gate 			tlp = lp;
267*7c478bd9Sstevel@tonic-gate 			if (tlp == NULL) {
268*7c478bd9Sstevel@tonic-gate 				tlp = kmem_cache_alloc(lnode_cache, KM_SLEEP);
269*7c478bd9Sstevel@tonic-gate 			}
270*7c478bd9Sstevel@tonic-gate 			if (nvp == NULL) {
271*7c478bd9Sstevel@tonic-gate 				nvp = vn_alloc(KM_SLEEP);
272*7c478bd9Sstevel@tonic-gate 			}
273*7c478bd9Sstevel@tonic-gate 			TABLE_LOCK_ENTER(vp, li);
274*7c478bd9Sstevel@tonic-gate 			if ((lp = lfind(vp, li)) != NULL) {
275*7c478bd9Sstevel@tonic-gate 				kmem_cache_free(lnode_cache, tlp);
276*7c478bd9Sstevel@tonic-gate 				vn_free(nvp);
277*7c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
278*7c478bd9Sstevel@tonic-gate 				goto found_lnode;
279*7c478bd9Sstevel@tonic-gate 			}
280*7c478bd9Sstevel@tonic-gate 			lp = tlp;
281*7c478bd9Sstevel@tonic-gate 		}
282*7c478bd9Sstevel@tonic-gate 		atomic_add_32(&li->li_refct, 1);
283*7c478bd9Sstevel@tonic-gate 		vfsp = makelfsnode(vp->v_vfsp, li);
284*7c478bd9Sstevel@tonic-gate 		lp->lo_vnode = nvp;
285*7c478bd9Sstevel@tonic-gate 		VN_SET_VFS_TYPE_DEV(nvp, vfsp, vp->v_type, vp->v_rdev);
286*7c478bd9Sstevel@tonic-gate 		nvp->v_flag |= (vp->v_flag & (VNOMOUNT|VNOMAP|VDIROPEN));
287*7c478bd9Sstevel@tonic-gate 		vn_setops(nvp, lo_vnodeops);
288*7c478bd9Sstevel@tonic-gate 		nvp->v_data = (caddr_t)lp;
289*7c478bd9Sstevel@tonic-gate 		lp->lo_vp = vp;
290*7c478bd9Sstevel@tonic-gate 		lp->lo_looping = 0;
291*7c478bd9Sstevel@tonic-gate 		lsave(lp, li);
292*7c478bd9Sstevel@tonic-gate 		vn_exists(vp);
293*7c478bd9Sstevel@tonic-gate 	} else {
294*7c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate found_lnode:
298*7c478bd9Sstevel@tonic-gate 	TABLE_LOCK_EXIT(vp, li);
299*7c478bd9Sstevel@tonic-gate 	return (ltov(lp));
300*7c478bd9Sstevel@tonic-gate }
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate /*
303*7c478bd9Sstevel@tonic-gate  * Get/Make vfs structure for given real vfs
304*7c478bd9Sstevel@tonic-gate  */
305*7c478bd9Sstevel@tonic-gate static struct vfs *
306*7c478bd9Sstevel@tonic-gate makelfsnode(struct vfs *vfsp, struct loinfo *li)
307*7c478bd9Sstevel@tonic-gate {
308*7c478bd9Sstevel@tonic-gate 	struct lfsnode *lfs;
309*7c478bd9Sstevel@tonic-gate 	struct lfsnode *tlfs;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/*
312*7c478bd9Sstevel@tonic-gate 	 * Don't grab any locks for the fast (common) case.
313*7c478bd9Sstevel@tonic-gate 	 */
314*7c478bd9Sstevel@tonic-gate 	if (vfsp == li->li_realvfs)
315*7c478bd9Sstevel@tonic-gate 		return (li->li_mountvfs);
316*7c478bd9Sstevel@tonic-gate 	ASSERT(li->li_refct > 0);
317*7c478bd9Sstevel@tonic-gate 	mutex_enter(&li->li_lfslock);
318*7c478bd9Sstevel@tonic-gate 	if ((lfs = lfsfind(vfsp, li)) == NULL) {
319*7c478bd9Sstevel@tonic-gate 		mutex_exit(&li->li_lfslock);
320*7c478bd9Sstevel@tonic-gate 		lfs = kmem_zalloc(sizeof (*lfs), KM_SLEEP);
321*7c478bd9Sstevel@tonic-gate 		mutex_enter(&li->li_lfslock);
322*7c478bd9Sstevel@tonic-gate 		if ((tlfs = lfsfind(vfsp, li)) != NULL) {
323*7c478bd9Sstevel@tonic-gate 			kmem_free(lfs, sizeof (*lfs));
324*7c478bd9Sstevel@tonic-gate 			lfs = tlfs;
325*7c478bd9Sstevel@tonic-gate 			goto found_lfs;
326*7c478bd9Sstevel@tonic-gate 		}
327*7c478bd9Sstevel@tonic-gate 		lfs->lfs_realvfs = vfsp;
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 		/*
330*7c478bd9Sstevel@tonic-gate 		 * Even though the lfsnode is strictly speaking a private
331*7c478bd9Sstevel@tonic-gate 		 * implementation detail of lofs, it should behave as a regular
332*7c478bd9Sstevel@tonic-gate 		 * vfs_t for the benefit of the rest of the kernel.
333*7c478bd9Sstevel@tonic-gate 		 */
334*7c478bd9Sstevel@tonic-gate 		VFS_INIT(&lfs->lfs_vfs, lo_vfsops, (caddr_t)li);
335*7c478bd9Sstevel@tonic-gate 		lfs->lfs_vfs.vfs_fstype = li->li_mountvfs->vfs_fstype;
336*7c478bd9Sstevel@tonic-gate 		lfs->lfs_vfs.vfs_flag =
337*7c478bd9Sstevel@tonic-gate 			((vfsp->vfs_flag | li->li_mflag) & ~li->li_dflag) &
338*7c478bd9Sstevel@tonic-gate 			INHERIT_VFS_FLAG;
339*7c478bd9Sstevel@tonic-gate 		lfs->lfs_vfs.vfs_bsize = vfsp->vfs_bsize;
340*7c478bd9Sstevel@tonic-gate 		lfs->lfs_vfs.vfs_dev = vfsp->vfs_dev;
341*7c478bd9Sstevel@tonic-gate 		lfs->lfs_vfs.vfs_fsid = vfsp->vfs_fsid;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 		if (vfsp->vfs_mntpt != NULL) {
344*7c478bd9Sstevel@tonic-gate 			lfs->lfs_vfs.vfs_mntpt = vfs_getmntpoint(vfsp);
345*7c478bd9Sstevel@tonic-gate 			/* Leave a reference to the mountpoint */
346*7c478bd9Sstevel@tonic-gate 		}
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 		(void) VFS_ROOT(vfsp, &lfs->lfs_realrootvp);
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 		/*
351*7c478bd9Sstevel@tonic-gate 		 * We use 1 instead of 0 as the value to associate with
352*7c478bd9Sstevel@tonic-gate 		 * an idle lfs_vfs.  This is to prevent VFS_RELE()
353*7c478bd9Sstevel@tonic-gate 		 * trying to kmem_free() our lfs_t (which is the wrong
354*7c478bd9Sstevel@tonic-gate 		 * size).
355*7c478bd9Sstevel@tonic-gate 		 */
356*7c478bd9Sstevel@tonic-gate 		VFS_HOLD(&lfs->lfs_vfs);
357*7c478bd9Sstevel@tonic-gate 		lfs->lfs_next = li->li_lfs;
358*7c478bd9Sstevel@tonic-gate 		li->li_lfs = lfs;
359*7c478bd9Sstevel@tonic-gate 	}
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate found_lfs:
362*7c478bd9Sstevel@tonic-gate 	VFS_HOLD(&lfs->lfs_vfs);
363*7c478bd9Sstevel@tonic-gate 	mutex_exit(&li->li_lfslock);
364*7c478bd9Sstevel@tonic-gate 	return (&lfs->lfs_vfs);
365*7c478bd9Sstevel@tonic-gate }
366*7c478bd9Sstevel@tonic-gate 
367*7c478bd9Sstevel@tonic-gate /*
368*7c478bd9Sstevel@tonic-gate  * Free lfs node since no longer in use
369*7c478bd9Sstevel@tonic-gate  */
370*7c478bd9Sstevel@tonic-gate static void
371*7c478bd9Sstevel@tonic-gate freelfsnode(struct lfsnode *lfs, struct loinfo *li)
372*7c478bd9Sstevel@tonic-gate {
373*7c478bd9Sstevel@tonic-gate 	struct lfsnode *prev = NULL;
374*7c478bd9Sstevel@tonic-gate 	struct lfsnode *this;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&li->li_lfslock));
377*7c478bd9Sstevel@tonic-gate 	ASSERT(li->li_refct > 0);
378*7c478bd9Sstevel@tonic-gate 	for (this = li->li_lfs; this != NULL; this = this->lfs_next) {
379*7c478bd9Sstevel@tonic-gate 		if (this == lfs) {
380*7c478bd9Sstevel@tonic-gate 			ASSERT(lfs->lfs_vfs.vfs_count == 1);
381*7c478bd9Sstevel@tonic-gate 			if (prev == NULL)
382*7c478bd9Sstevel@tonic-gate 				li->li_lfs = lfs->lfs_next;
383*7c478bd9Sstevel@tonic-gate 			else
384*7c478bd9Sstevel@tonic-gate 				prev->lfs_next = lfs->lfs_next;
385*7c478bd9Sstevel@tonic-gate 			if (lfs->lfs_realrootvp != NULL) {
386*7c478bd9Sstevel@tonic-gate 				VN_RELE(lfs->lfs_realrootvp);
387*7c478bd9Sstevel@tonic-gate 			}
388*7c478bd9Sstevel@tonic-gate 			if (lfs->lfs_vfs.vfs_mntpt != NULL)
389*7c478bd9Sstevel@tonic-gate 				refstr_rele(lfs->lfs_vfs.vfs_mntpt);
390*7c478bd9Sstevel@tonic-gate 			sema_destroy(&lfs->lfs_vfs.vfs_reflock);
391*7c478bd9Sstevel@tonic-gate 			kmem_free(lfs, sizeof (struct lfsnode));
392*7c478bd9Sstevel@tonic-gate 			return;
393*7c478bd9Sstevel@tonic-gate 		}
394*7c478bd9Sstevel@tonic-gate 		prev = this;
395*7c478bd9Sstevel@tonic-gate 	}
396*7c478bd9Sstevel@tonic-gate 	panic("freelfsnode");
397*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
398*7c478bd9Sstevel@tonic-gate }
399*7c478bd9Sstevel@tonic-gate 
400*7c478bd9Sstevel@tonic-gate /*
401*7c478bd9Sstevel@tonic-gate  * Find lfs given real vfs and mount instance(li)
402*7c478bd9Sstevel@tonic-gate  */
403*7c478bd9Sstevel@tonic-gate static struct lfsnode *
404*7c478bd9Sstevel@tonic-gate lfsfind(struct vfs *vfsp, struct loinfo *li)
405*7c478bd9Sstevel@tonic-gate {
406*7c478bd9Sstevel@tonic-gate 	struct lfsnode *lfs;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&li->li_lfslock));
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	/*
411*7c478bd9Sstevel@tonic-gate 	 * We need to handle the case where a UFS filesystem was forced
412*7c478bd9Sstevel@tonic-gate 	 * unmounted and then a subsequent mount got the same vfs
413*7c478bd9Sstevel@tonic-gate 	 * structure.  If the new mount lies in the lofs hierarchy, then
414*7c478bd9Sstevel@tonic-gate 	 * this will confuse lofs, because the original vfsp (of the
415*7c478bd9Sstevel@tonic-gate 	 * forced unmounted filesystem) is still around. We check for
416*7c478bd9Sstevel@tonic-gate 	 * this condition here.
417*7c478bd9Sstevel@tonic-gate 	 *
418*7c478bd9Sstevel@tonic-gate 	 * If we find a cache vfsp hit, then we check to see if the
419*7c478bd9Sstevel@tonic-gate 	 * cached filesystem was forced unmounted. Skip all such
420*7c478bd9Sstevel@tonic-gate 	 * entries. This should be safe to do since no
421*7c478bd9Sstevel@tonic-gate 	 * makelonode()->makelfsnode()->lfsfind() calls should be
422*7c478bd9Sstevel@tonic-gate 	 * generated for such force-unmounted filesystems (because (ufs)
423*7c478bd9Sstevel@tonic-gate 	 * lookup would've returned an error).
424*7c478bd9Sstevel@tonic-gate 	 */
425*7c478bd9Sstevel@tonic-gate 	for (lfs = li->li_lfs; lfs != NULL; lfs = lfs->lfs_next) {
426*7c478bd9Sstevel@tonic-gate 		if (lfs->lfs_realvfs == vfsp) {
427*7c478bd9Sstevel@tonic-gate 			struct vnode *realvp;
428*7c478bd9Sstevel@tonic-gate 
429*7c478bd9Sstevel@tonic-gate 			realvp = lfs->lfs_realrootvp;
430*7c478bd9Sstevel@tonic-gate 			if (realvp == NULL)
431*7c478bd9Sstevel@tonic-gate 				continue;
432*7c478bd9Sstevel@tonic-gate 			if (realvp->v_vfsp == NULL || realvp->v_type == VBAD)
433*7c478bd9Sstevel@tonic-gate 				continue;
434*7c478bd9Sstevel@tonic-gate 			return (lfs);
435*7c478bd9Sstevel@tonic-gate 		}
436*7c478bd9Sstevel@tonic-gate 	}
437*7c478bd9Sstevel@tonic-gate 	return (NULL);
438*7c478bd9Sstevel@tonic-gate }
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate /*
441*7c478bd9Sstevel@tonic-gate  * Find real vfs given loopback vfs
442*7c478bd9Sstevel@tonic-gate  */
443*7c478bd9Sstevel@tonic-gate struct vfs *
444*7c478bd9Sstevel@tonic-gate lo_realvfs(struct vfs *vfsp, struct vnode **realrootvpp)
445*7c478bd9Sstevel@tonic-gate {
446*7c478bd9Sstevel@tonic-gate 	struct loinfo *li = vtoli(vfsp);
447*7c478bd9Sstevel@tonic-gate 	struct lfsnode *lfs;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	ASSERT(li->li_refct > 0);
450*7c478bd9Sstevel@tonic-gate 	if (vfsp == li->li_mountvfs) {
451*7c478bd9Sstevel@tonic-gate 		if (realrootvpp != NULL)
452*7c478bd9Sstevel@tonic-gate 			*realrootvpp = vtol(li->li_rootvp)->lo_vp;
453*7c478bd9Sstevel@tonic-gate 		return (li->li_realvfs);
454*7c478bd9Sstevel@tonic-gate 	}
455*7c478bd9Sstevel@tonic-gate 	mutex_enter(&li->li_lfslock);
456*7c478bd9Sstevel@tonic-gate 	for (lfs = li->li_lfs; lfs != NULL; lfs = lfs->lfs_next) {
457*7c478bd9Sstevel@tonic-gate 		if (vfsp == &lfs->lfs_vfs) {
458*7c478bd9Sstevel@tonic-gate 			if (realrootvpp != NULL)
459*7c478bd9Sstevel@tonic-gate 				*realrootvpp = lfs->lfs_realrootvp;
460*7c478bd9Sstevel@tonic-gate 			mutex_exit(&li->li_lfslock);
461*7c478bd9Sstevel@tonic-gate 			return (lfs->lfs_realvfs);
462*7c478bd9Sstevel@tonic-gate 		}
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate 	panic("lo_realvfs");
465*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
466*7c478bd9Sstevel@tonic-gate }
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate /*
469*7c478bd9Sstevel@tonic-gate  * Lnode lookup stuff.
470*7c478bd9Sstevel@tonic-gate  * These routines maintain a table of lnodes hashed by vp so
471*7c478bd9Sstevel@tonic-gate  * that the lnode for a vp can be found if it already exists.
472*7c478bd9Sstevel@tonic-gate  *
473*7c478bd9Sstevel@tonic-gate  * NB: A lofs shadow vnode causes exactly one VN_HOLD() on the
474*7c478bd9Sstevel@tonic-gate  * underlying vnode.
475*7c478bd9Sstevel@tonic-gate  */
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate /*
478*7c478bd9Sstevel@tonic-gate  * Retire old hashtables.
479*7c478bd9Sstevel@tonic-gate  */
480*7c478bd9Sstevel@tonic-gate static void
481*7c478bd9Sstevel@tonic-gate lretire(struct loinfo *li, struct lobucket *table, uint_t size)
482*7c478bd9Sstevel@tonic-gate {
483*7c478bd9Sstevel@tonic-gate 	struct lo_retired_ht *lrhp;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	lrhp = kmem_alloc(sizeof (*lrhp), KM_SLEEP);
486*7c478bd9Sstevel@tonic-gate 	lrhp->lrh_table = table;
487*7c478bd9Sstevel@tonic-gate 	lrhp->lrh_size = size;
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	mutex_enter(&li->li_htlock);
490*7c478bd9Sstevel@tonic-gate 	lrhp->lrh_next = li->li_retired;
491*7c478bd9Sstevel@tonic-gate 	li->li_retired = lrhp;
492*7c478bd9Sstevel@tonic-gate 	mutex_exit(&li->li_htlock);
493*7c478bd9Sstevel@tonic-gate }
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate /*
496*7c478bd9Sstevel@tonic-gate  * Grow the hashtable.
497*7c478bd9Sstevel@tonic-gate  */
498*7c478bd9Sstevel@tonic-gate static void
499*7c478bd9Sstevel@tonic-gate lgrow(struct loinfo *li, uint_t newsize)
500*7c478bd9Sstevel@tonic-gate {
501*7c478bd9Sstevel@tonic-gate 	uint_t oldsize;
502*7c478bd9Sstevel@tonic-gate 	uint_t i;
503*7c478bd9Sstevel@tonic-gate 	struct lobucket *oldtable, *newtable;
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	/*
506*7c478bd9Sstevel@tonic-gate 	 * It's OK to not have enough memory to resize the hashtable.
507*7c478bd9Sstevel@tonic-gate 	 * We'll go down this path the next time we add something to the
508*7c478bd9Sstevel@tonic-gate 	 * table, and retry the allocation then.
509*7c478bd9Sstevel@tonic-gate 	 */
510*7c478bd9Sstevel@tonic-gate 	if ((newtable = kmem_zalloc(newsize * sizeof (*li->li_hashtable),
511*7c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL)
512*7c478bd9Sstevel@tonic-gate 		return;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	mutex_enter(&li->li_htlock);
515*7c478bd9Sstevel@tonic-gate 	if (newsize <= li->li_htsize) {
516*7c478bd9Sstevel@tonic-gate 		mutex_exit(&li->li_htlock);
517*7c478bd9Sstevel@tonic-gate 		kmem_free(newtable, newsize * sizeof (*li->li_hashtable));
518*7c478bd9Sstevel@tonic-gate 		return;
519*7c478bd9Sstevel@tonic-gate 	}
520*7c478bd9Sstevel@tonic-gate 	oldsize = li->li_htsize;
521*7c478bd9Sstevel@tonic-gate 	oldtable = li->li_hashtable;
522*7c478bd9Sstevel@tonic-gate 
523*7c478bd9Sstevel@tonic-gate 	/*
524*7c478bd9Sstevel@tonic-gate 	 * Grab all locks so TABLE_LOCK_ENTER() calls block until the
525*7c478bd9Sstevel@tonic-gate 	 * resize is complete.
526*7c478bd9Sstevel@tonic-gate 	 */
527*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < oldsize; i++)
528*7c478bd9Sstevel@tonic-gate 		mutex_enter(&oldtable[i].lh_lock);
529*7c478bd9Sstevel@tonic-gate 	/*
530*7c478bd9Sstevel@tonic-gate 	 * li->li_hashtable gets set before li->li_htsize, so in the
531*7c478bd9Sstevel@tonic-gate 	 * time between the two assignments, callers of
532*7c478bd9Sstevel@tonic-gate 	 * TABLE_LOCK_ENTER() cannot hash to a bucket beyond oldsize,
533*7c478bd9Sstevel@tonic-gate 	 * hence we only need to grab the locks up to oldsize.
534*7c478bd9Sstevel@tonic-gate 	 */
535*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < oldsize; i++)
536*7c478bd9Sstevel@tonic-gate 		mutex_enter(&newtable[i].lh_lock);
537*7c478bd9Sstevel@tonic-gate 	/*
538*7c478bd9Sstevel@tonic-gate 	 * Rehash.
539*7c478bd9Sstevel@tonic-gate 	 */
540*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < oldsize; i++) {
541*7c478bd9Sstevel@tonic-gate 		lnode_t *tlp, *nlp;
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 		for (tlp = oldtable[i].lh_chain; tlp != NULL; tlp = nlp) {
544*7c478bd9Sstevel@tonic-gate 			uint_t hash = ltablehash(tlp->lo_vp, newsize);
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 			nlp = tlp->lo_next;
547*7c478bd9Sstevel@tonic-gate 			tlp->lo_next = newtable[hash].lh_chain;
548*7c478bd9Sstevel@tonic-gate 			newtable[hash].lh_chain = tlp;
549*7c478bd9Sstevel@tonic-gate 			newtable[hash].lh_count++;
550*7c478bd9Sstevel@tonic-gate 		}
551*7c478bd9Sstevel@tonic-gate 	}
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	/*
554*7c478bd9Sstevel@tonic-gate 	 * As soon as we store the new hashtable, future locking operations
555*7c478bd9Sstevel@tonic-gate 	 * will use it.  Therefore, we must ensure that all the state we've
556*7c478bd9Sstevel@tonic-gate 	 * just established reaches global visibility before the new hashtable
557*7c478bd9Sstevel@tonic-gate 	 * does.
558*7c478bd9Sstevel@tonic-gate 	 */
559*7c478bd9Sstevel@tonic-gate 	membar_producer();
560*7c478bd9Sstevel@tonic-gate 	li->li_hashtable = newtable;
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	/*
563*7c478bd9Sstevel@tonic-gate 	 * table_lock_enter() relies on the fact that li->li_hashtable
564*7c478bd9Sstevel@tonic-gate 	 * is set to its new value before li->li_htsize.
565*7c478bd9Sstevel@tonic-gate 	 */
566*7c478bd9Sstevel@tonic-gate 	membar_producer();
567*7c478bd9Sstevel@tonic-gate 	li->li_htsize = newsize;
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	/*
570*7c478bd9Sstevel@tonic-gate 	 * The new state is consistent now, so we can drop all the locks.
571*7c478bd9Sstevel@tonic-gate 	 */
572*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < oldsize; i++) {
573*7c478bd9Sstevel@tonic-gate 		mutex_exit(&newtable[i].lh_lock);
574*7c478bd9Sstevel@tonic-gate 		mutex_exit(&oldtable[i].lh_lock);
575*7c478bd9Sstevel@tonic-gate 	}
576*7c478bd9Sstevel@tonic-gate 	mutex_exit(&li->li_htlock);
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate 	lretire(li, oldtable, oldsize);
579*7c478bd9Sstevel@tonic-gate }
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate /*
582*7c478bd9Sstevel@tonic-gate  * Put a lnode in the table
583*7c478bd9Sstevel@tonic-gate  */
584*7c478bd9Sstevel@tonic-gate static void
585*7c478bd9Sstevel@tonic-gate lsave(lnode_t *lp, struct loinfo *li)
586*7c478bd9Sstevel@tonic-gate {
587*7c478bd9Sstevel@tonic-gate 	ASSERT(lp->lo_vp);
588*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(TABLE_LOCK(lp->lo_vp, li)));
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate #ifdef LODEBUG
591*7c478bd9Sstevel@tonic-gate 	lo_dprint(4, "lsave lp %p hash %d\n",
592*7c478bd9Sstevel@tonic-gate 			lp, ltablehash(lp->lo_vp, li));
593*7c478bd9Sstevel@tonic-gate #endif
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	TABLE_COUNT(lp->lo_vp, li)++;
596*7c478bd9Sstevel@tonic-gate 	lp->lo_next = TABLE_BUCKET(lp->lo_vp, li);
597*7c478bd9Sstevel@tonic-gate 	TABLE_BUCKET(lp->lo_vp, li) = lp;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 	if (li->li_refct > (li->li_htsize << lo_resize_threshold)) {
600*7c478bd9Sstevel@tonic-gate 		TABLE_LOCK_EXIT(lp->lo_vp, li);
601*7c478bd9Sstevel@tonic-gate 		lgrow(li, li->li_htsize << lo_resize_factor);
602*7c478bd9Sstevel@tonic-gate 		TABLE_LOCK_ENTER(lp->lo_vp, li);
603*7c478bd9Sstevel@tonic-gate 	}
604*7c478bd9Sstevel@tonic-gate }
605*7c478bd9Sstevel@tonic-gate 
606*7c478bd9Sstevel@tonic-gate /*
607*7c478bd9Sstevel@tonic-gate  * Our version of vfs_rele() that stops at 1 instead of 0, and calls
608*7c478bd9Sstevel@tonic-gate  * freelfsnode() instead of kmem_free().
609*7c478bd9Sstevel@tonic-gate  */
610*7c478bd9Sstevel@tonic-gate static void
611*7c478bd9Sstevel@tonic-gate lfs_rele(struct lfsnode *lfs, struct loinfo *li)
612*7c478bd9Sstevel@tonic-gate {
613*7c478bd9Sstevel@tonic-gate 	vfs_t *vfsp = &lfs->lfs_vfs;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&li->li_lfslock));
616*7c478bd9Sstevel@tonic-gate 	ASSERT(vfsp->vfs_count > 1);
617*7c478bd9Sstevel@tonic-gate 	if (atomic_add_32_nv(&vfsp->vfs_count, -1) == 1)
618*7c478bd9Sstevel@tonic-gate 		freelfsnode(lfs, li);
619*7c478bd9Sstevel@tonic-gate }
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate /*
622*7c478bd9Sstevel@tonic-gate  * Remove a lnode from the table
623*7c478bd9Sstevel@tonic-gate  */
624*7c478bd9Sstevel@tonic-gate void
625*7c478bd9Sstevel@tonic-gate freelonode(lnode_t *lp)
626*7c478bd9Sstevel@tonic-gate {
627*7c478bd9Sstevel@tonic-gate 	lnode_t *lt;
628*7c478bd9Sstevel@tonic-gate 	lnode_t *ltprev = NULL;
629*7c478bd9Sstevel@tonic-gate 	struct lfsnode *lfs, *nextlfs;
630*7c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
631*7c478bd9Sstevel@tonic-gate 	struct vnode *vp = ltov(lp);
632*7c478bd9Sstevel@tonic-gate 	struct vnode *realvp = realvp(vp);
633*7c478bd9Sstevel@tonic-gate 	struct loinfo *li = vtoli(vp->v_vfsp);
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate #ifdef LODEBUG
636*7c478bd9Sstevel@tonic-gate 	lo_dprint(4, "freelonode lp %p hash %d\n",
637*7c478bd9Sstevel@tonic-gate 			lp, ltablehash(lp->lo_vp, li));
638*7c478bd9Sstevel@tonic-gate #endif
639*7c478bd9Sstevel@tonic-gate 	TABLE_LOCK_ENTER(lp->lo_vp, li);
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
642*7c478bd9Sstevel@tonic-gate 	if (vp->v_count > 1) {
643*7c478bd9Sstevel@tonic-gate 		vp->v_count--;	/* release our hold from vn_rele */
644*7c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
645*7c478bd9Sstevel@tonic-gate 		TABLE_LOCK_EXIT(lp->lo_vp, li);
646*7c478bd9Sstevel@tonic-gate 		return;
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
649*7c478bd9Sstevel@tonic-gate 
650*7c478bd9Sstevel@tonic-gate 	for (lt = TABLE_BUCKET(lp->lo_vp, li); lt != NULL;
651*7c478bd9Sstevel@tonic-gate 	    ltprev = lt, lt = lt->lo_next) {
652*7c478bd9Sstevel@tonic-gate 		if (lt == lp) {
653*7c478bd9Sstevel@tonic-gate #ifdef LODEBUG
654*7c478bd9Sstevel@tonic-gate 			lo_dprint(4, "freeing %p, vfsp %p\n",
655*7c478bd9Sstevel@tonic-gate 					vp, vp->v_vfsp);
656*7c478bd9Sstevel@tonic-gate #endif
657*7c478bd9Sstevel@tonic-gate 			atomic_add_32(&li->li_refct, -1);
658*7c478bd9Sstevel@tonic-gate 			vfsp = vp->v_vfsp;
659*7c478bd9Sstevel@tonic-gate 			vn_invalid(vp);
660*7c478bd9Sstevel@tonic-gate 			if (vfsp != li->li_mountvfs) {
661*7c478bd9Sstevel@tonic-gate 				mutex_enter(&li->li_lfslock);
662*7c478bd9Sstevel@tonic-gate 				/*
663*7c478bd9Sstevel@tonic-gate 				 * Check for unused lfs
664*7c478bd9Sstevel@tonic-gate 				 */
665*7c478bd9Sstevel@tonic-gate 				lfs = li->li_lfs;
666*7c478bd9Sstevel@tonic-gate 				while (lfs != NULL) {
667*7c478bd9Sstevel@tonic-gate 					nextlfs = lfs->lfs_next;
668*7c478bd9Sstevel@tonic-gate 					if (vfsp == &lfs->lfs_vfs) {
669*7c478bd9Sstevel@tonic-gate 						lfs_rele(lfs, li);
670*7c478bd9Sstevel@tonic-gate 						break;
671*7c478bd9Sstevel@tonic-gate 					}
672*7c478bd9Sstevel@tonic-gate 					if (lfs->lfs_vfs.vfs_count == 1) {
673*7c478bd9Sstevel@tonic-gate 						/*
674*7c478bd9Sstevel@tonic-gate 						 * Lfs is idle
675*7c478bd9Sstevel@tonic-gate 						 */
676*7c478bd9Sstevel@tonic-gate 						freelfsnode(lfs, li);
677*7c478bd9Sstevel@tonic-gate 					}
678*7c478bd9Sstevel@tonic-gate 					lfs = nextlfs;
679*7c478bd9Sstevel@tonic-gate 				}
680*7c478bd9Sstevel@tonic-gate 				mutex_exit(&li->li_lfslock);
681*7c478bd9Sstevel@tonic-gate 			}
682*7c478bd9Sstevel@tonic-gate 			if (ltprev == NULL) {
683*7c478bd9Sstevel@tonic-gate 				TABLE_BUCKET(lt->lo_vp, li) = lt->lo_next;
684*7c478bd9Sstevel@tonic-gate 			} else {
685*7c478bd9Sstevel@tonic-gate 				ltprev->lo_next = lt->lo_next;
686*7c478bd9Sstevel@tonic-gate 			}
687*7c478bd9Sstevel@tonic-gate 			TABLE_COUNT(lt->lo_vp, li)--;
688*7c478bd9Sstevel@tonic-gate 			TABLE_LOCK_EXIT(lt->lo_vp, li);
689*7c478bd9Sstevel@tonic-gate 			kmem_cache_free(lnode_cache, lt);
690*7c478bd9Sstevel@tonic-gate 			vn_free(vp);
691*7c478bd9Sstevel@tonic-gate 			VN_RELE(realvp);
692*7c478bd9Sstevel@tonic-gate 			return;
693*7c478bd9Sstevel@tonic-gate 		}
694*7c478bd9Sstevel@tonic-gate 	}
695*7c478bd9Sstevel@tonic-gate 	panic("freelonode");
696*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
697*7c478bd9Sstevel@tonic-gate }
698*7c478bd9Sstevel@tonic-gate 
699*7c478bd9Sstevel@tonic-gate /*
700*7c478bd9Sstevel@tonic-gate  * Lookup a lnode by vp
701*7c478bd9Sstevel@tonic-gate  */
702*7c478bd9Sstevel@tonic-gate static lnode_t *
703*7c478bd9Sstevel@tonic-gate lfind(struct vnode *vp, struct loinfo *li)
704*7c478bd9Sstevel@tonic-gate {
705*7c478bd9Sstevel@tonic-gate 	lnode_t *lt;
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(TABLE_LOCK(vp, li)));
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	lt = TABLE_BUCKET(vp, li);
710*7c478bd9Sstevel@tonic-gate 	while (lt != NULL) {
711*7c478bd9Sstevel@tonic-gate 		if (lt->lo_vp == vp) {
712*7c478bd9Sstevel@tonic-gate 			VN_HOLD(ltov(lt));
713*7c478bd9Sstevel@tonic-gate 			return (lt);
714*7c478bd9Sstevel@tonic-gate 		}
715*7c478bd9Sstevel@tonic-gate 		lt = lt->lo_next;
716*7c478bd9Sstevel@tonic-gate 	}
717*7c478bd9Sstevel@tonic-gate 	return (NULL);
718*7c478bd9Sstevel@tonic-gate }
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate #ifdef	LODEBUG
721*7c478bd9Sstevel@tonic-gate static int lofsdebug;
722*7c478bd9Sstevel@tonic-gate #endif	/* LODEBUG */
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate /*
725*7c478bd9Sstevel@tonic-gate  * Utilities used by both client and server
726*7c478bd9Sstevel@tonic-gate  * Standard levels:
727*7c478bd9Sstevel@tonic-gate  * 0) no debugging
728*7c478bd9Sstevel@tonic-gate  * 1) hard failures
729*7c478bd9Sstevel@tonic-gate  * 2) soft failures
730*7c478bd9Sstevel@tonic-gate  * 3) current test software
731*7c478bd9Sstevel@tonic-gate  * 4) main procedure entry points
732*7c478bd9Sstevel@tonic-gate  * 5) main procedure exit points
733*7c478bd9Sstevel@tonic-gate  * 6) utility procedure entry points
734*7c478bd9Sstevel@tonic-gate  * 7) utility procedure exit points
735*7c478bd9Sstevel@tonic-gate  * 8) obscure procedure entry points
736*7c478bd9Sstevel@tonic-gate  * 9) obscure procedure exit points
737*7c478bd9Sstevel@tonic-gate  * 10) random stuff
738*7c478bd9Sstevel@tonic-gate  * 11) all <= 1
739*7c478bd9Sstevel@tonic-gate  * 12) all <= 2
740*7c478bd9Sstevel@tonic-gate  * 13) all <= 3
741*7c478bd9Sstevel@tonic-gate  * ...
742*7c478bd9Sstevel@tonic-gate  */
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate #ifdef LODEBUG
745*7c478bd9Sstevel@tonic-gate /*VARARGS2*/
746*7c478bd9Sstevel@tonic-gate lo_dprint(level, str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
747*7c478bd9Sstevel@tonic-gate 	int level;
748*7c478bd9Sstevel@tonic-gate 	char *str;
749*7c478bd9Sstevel@tonic-gate 	int a1, a2, a3, a4, a5, a6, a7, a8, a9;
750*7c478bd9Sstevel@tonic-gate {
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate 	if (lofsdebug == level || (lofsdebug > 10 && (lofsdebug - 10) >= level))
753*7c478bd9Sstevel@tonic-gate 		printf(str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
754*7c478bd9Sstevel@tonic-gate }
755*7c478bd9Sstevel@tonic-gate #endif
756