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