lofs_subr.c revision 1a5e258f5471356ca102c7176637cdce45bac147
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER START
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The contents of this file are subject to the terms of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Common Development and Distribution License (the "License").
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You may not use this file except in compliance with the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
269473047d747f7815af570197e4ef7322d3632cEvan Yan * or http://www.opensolaris.org/os/licensing.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * See the License for the specific language governing permissions
269473047d747f7815af570197e4ef7322d3632cEvan Yan * and limitations under the License.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * When distributing Covered Code, include this CDDL HEADER in each
269473047d747f7815af570197e4ef7322d3632cEvan Yan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If applicable, add the following below this CDDL HEADER, with the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * fields enclosed by brackets "[]" replaced with your own identifying
269473047d747f7815af570197e4ef7322d3632cEvan Yan * information: Portions Copyright [yyyy] [name of copyright owner]
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * CDDL HEADER END
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Use is subject to license terms.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The idea behind composition-based stacked filesystems is to add a
269473047d747f7815af570197e4ef7322d3632cEvan Yan * vnode to the stack of vnodes for each mount. These vnodes have their
269473047d747f7815af570197e4ef7322d3632cEvan Yan * own set of mount options and filesystem-specific functions, so they
269473047d747f7815af570197e4ef7322d3632cEvan Yan * can modify data or operations before they are passed along. Such a
269473047d747f7815af570197e4ef7322d3632cEvan Yan * filesystem must maintain a mapping from the underlying vnodes to its
269473047d747f7815af570197e4ef7322d3632cEvan Yan * interposing vnodes.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * In lofs, this mapping is implemented by a hashtable. Each bucket
269473047d747f7815af570197e4ef7322d3632cEvan Yan * contains a count of the number of nodes currently contained, the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * chain of vnodes, and a lock to protect the list of vnodes. The
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hashtable dynamically grows if the number of vnodes in the table as a
269473047d747f7815af570197e4ef7322d3632cEvan Yan * whole exceeds the size of the table left-shifted by
269473047d747f7815af570197e4ef7322d3632cEvan Yan * lo_resize_threshold. In order to minimize lock contention, there is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * no global lock protecting the hashtable, hence obtaining the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * per-bucket locks consists of a dance to make sure we've actually
269473047d747f7815af570197e4ef7322d3632cEvan Yan * locked the correct bucket. Acquiring a bucket lock doesn't involve
269473047d747f7815af570197e4ef7322d3632cEvan Yan * locking the hashtable itself, so we refrain from freeing old
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hashtables, and store them in a linked list of retired hashtables;
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the list is freed when the filesystem is unmounted.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/param.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/kmem.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/vfs.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/vnode.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/cmn_err.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/systm.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/t_lock.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/debug.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/atomic.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/fs/lofs_node.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan#include <sys/fs/lofs_info.h>
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Due to the hashing algorithm, the size of the hash table needs to be a
269473047d747f7815af570197e4ef7322d3632cEvan Yan * power of 2.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan#define LOFS_DEFAULT_HTSIZE (1 << 6)
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan#define ltablehash(vp, tblsz) ((((intptr_t)(vp))>>10) & ((tblsz)-1))
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The following macros can only be safely used when the desired bucket
269473047d747f7815af570197e4ef7322d3632cEvan Yan * is already locked.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The lock in the hashtable associated with the given vnode.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan#define TABLE_LOCK(vp, li) \
269473047d747f7815af570197e4ef7322d3632cEvan Yan (&(li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_lock)
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * The bucket in the hashtable that the given vnode hashes to.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan#define TABLE_BUCKET(vp, li) \
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_chain)
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Number of elements currently in the bucket that the vnode hashes to.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan#define TABLE_COUNT(vp, li) \
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((li)->li_hashtable[ltablehash((vp), (li)->li_htsize)].lh_count)
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Grab/Drop the lock for the bucket this vnode hashes to.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan#define TABLE_LOCK_ENTER(vp, li) table_lock_enter(vp, li)
269473047d747f7815af570197e4ef7322d3632cEvan Yan#define TABLE_LOCK_EXIT(vp, li) \
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&(li)->li_hashtable[ltablehash((vp), \
269473047d747f7815af570197e4ef7322d3632cEvan Yan (li)->li_htsize)].lh_lock)
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic lnode_t *lfind(struct vnode *, struct loinfo *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void lsave(lnode_t *, struct loinfo *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic struct vfs *makelfsnode(struct vfs *, struct loinfo *);
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic struct lfsnode *lfsfind(struct vfs *, struct loinfo *);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanuint_t lo_resize_threshold = 1;
269473047d747f7815af570197e4ef7322d3632cEvan Yanuint_t lo_resize_factor = 2;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic kmem_cache_t *lnode_cache;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Since the hashtable itself isn't protected by a lock, obtaining a
269473047d747f7815af570197e4ef7322d3632cEvan Yan * per-bucket lock proceeds as follows:
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (a) li->li_htlock protects li->li_hashtable, li->li_htsize, and
269473047d747f7815af570197e4ef7322d3632cEvan Yan * li->li_retired.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (b) Per-bucket locks (lh_lock) protect the contents of the bucket.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (c) Locking order for resizing the hashtable is li_htlock then
269473047d747f7815af570197e4ef7322d3632cEvan Yan * lh_lock.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * To grab the bucket lock we:
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (1) Stash away the htsize and the pointer to the hashtable to make
269473047d747f7815af570197e4ef7322d3632cEvan Yan * sure neither change while we're using them.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (2) lgrow() updates the pointer to the hashtable before it updates
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the size: the worst case scenario is that we have the wrong size (but
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the correct table), so we hash to the wrong bucket, grab the wrong
269473047d747f7815af570197e4ef7322d3632cEvan Yan * lock, and then realize that things have changed, rewind and start
269473047d747f7815af570197e4ef7322d3632cEvan Yan * again. If both the size and the table changed since we loaded them,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * we'll realize that too and restart.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (3) The protocol for growing the hashtable involves holding *all* the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * locks in the table, hence the unlocking code (TABLE_LOCK_EXIT())
269473047d747f7815af570197e4ef7322d3632cEvan Yan * doesn't need to do any dances, since neither the table nor the size
269473047d747f7815af570197e4ef7322d3632cEvan Yan * can change while any bucket lock is held.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (4) If the hashtable is growing (by thread t1) while another thread
269473047d747f7815af570197e4ef7322d3632cEvan Yan * (t2) is trying to grab a bucket lock, t2 might have a stale reference
269473047d747f7815af570197e4ef7322d3632cEvan Yan * to li->li_htsize:
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * - t1 grabs all locks in lgrow()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * - t2 loads li->li_htsize and li->li_hashtable
269473047d747f7815af570197e4ef7322d3632cEvan Yan * - t1 changes li->hashtable
269473047d747f7815af570197e4ef7322d3632cEvan Yan * - t2 loads from an offset in the "stale" hashtable and tries to grab
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the relevant mutex.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If t1 had free'd the stale hashtable, t2 would be in trouble. Hence,
269473047d747f7815af570197e4ef7322d3632cEvan Yan * stale hashtables are not freed but stored in a list of "retired"
269473047d747f7815af570197e4ef7322d3632cEvan Yan * hashtables, which is emptied when the filesystem is unmounted.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yantable_lock_enter(vnode_t *vp, struct loinfo *li)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lobucket *chain;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t htsize;
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t hash;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (;;) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan htsize = li->li_htsize;
269473047d747f7815af570197e4ef7322d3632cEvan Yan membar_consumer();
269473047d747f7815af570197e4ef7322d3632cEvan Yan chain = (struct lobucket *)li->li_hashtable;
269473047d747f7815af570197e4ef7322d3632cEvan Yan hash = ltablehash(vp, htsize);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&chain[hash].lh_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (li->li_hashtable == chain && li->li_htsize == htsize)
269473047d747f7815af570197e4ef7322d3632cEvan Yan break;
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&chain[hash].lh_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanlofs_subrinit(void)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Initialize the cache.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan lnode_cache = kmem_cache_create("lnode_cache", sizeof (lnode_t),
269473047d747f7815af570197e4ef7322d3632cEvan Yan 0, NULL, NULL, NULL, NULL, NULL, 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanlofs_subrfini(void)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_cache_destroy(lnode_cache);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Initialize a (struct loinfo), and initialize the hashtable to have
269473047d747f7815af570197e4ef7322d3632cEvan Yan * htsize buckets.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanlsetup(struct loinfo *li, uint_t htsize)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_refct = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_lfs = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (htsize == 0)
269473047d747f7815af570197e4ef7322d3632cEvan Yan htsize = LOFS_DEFAULT_HTSIZE;
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_htsize = htsize;
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_hashtable = kmem_zalloc(htsize * sizeof (*li->li_hashtable),
269473047d747f7815af570197e4ef7322d3632cEvan Yan KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_init(&li->li_lfslock, NULL, MUTEX_DEFAULT, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_init(&li->li_htlock, NULL, MUTEX_DEFAULT, NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_retired = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Destroy a (struct loinfo)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanvoid
269473047d747f7815af570197e4ef7322d3632cEvan Yanldestroy(struct loinfo *li)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan uint_t i, htsize;
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lobucket *table;
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lo_retired_ht *lrhp, *trhp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_destroy(&li->li_htlock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_destroy(&li->li_lfslock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan htsize = li->li_htsize;
269473047d747f7815af570197e4ef7322d3632cEvan Yan table = li->li_hashtable;
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (i = 0; i < htsize; i++)
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_destroy(&table[i].lh_lock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(table, htsize * sizeof (*li->li_hashtable));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Free the retired hashtables.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan lrhp = li->li_retired;
269473047d747f7815af570197e4ef7322d3632cEvan Yan while (lrhp != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan trhp = lrhp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lrhp = lrhp->lrh_next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(trhp->lrh_table,
269473047d747f7815af570197e4ef7322d3632cEvan Yan trhp->lrh_size * sizeof (*li->li_hashtable));
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(trhp, sizeof (*trhp));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_retired = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Return a looped back vnode for the given vnode.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If no lnode exists for this vnode create one and put it
269473047d747f7815af570197e4ef7322d3632cEvan Yan * in a table hashed by vnode. If the lnode for
269473047d747f7815af570197e4ef7322d3632cEvan Yan * this vnode is already in the table return it (ref count is
269473047d747f7815af570197e4ef7322d3632cEvan Yan * incremented by lfind). The lnode will be flushed from the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * table when lo_inactive calls freelonode. The creation of
269473047d747f7815af570197e4ef7322d3632cEvan Yan * a new lnode can be forced via the LOF_FORCE flag even if
269473047d747f7815af570197e4ef7322d3632cEvan Yan * the vnode exists in the table. This is used in the creation
269473047d747f7815af570197e4ef7322d3632cEvan Yan * of a terminating lnode when looping is detected. A unique
269473047d747f7815af570197e4ef7322d3632cEvan Yan * lnode is required for the correct evaluation of the current
269473047d747f7815af570197e4ef7322d3632cEvan Yan * working directory.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NOTE: vp is assumed to be a held vnode.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstruct vnode *
269473047d747f7815af570197e4ef7322d3632cEvan Yanmakelonode(struct vnode *vp, struct loinfo *li, int flag)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan lnode_t *lp, *tlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct vfs *vfsp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan vnode_t *nvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan TABLE_LOCK_ENTER(vp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flag != LOF_FORCE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp = lfind(vp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((flag == LOF_FORCE) || (lp == NULL)) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Optimistically assume that we won't need to sleep.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp = kmem_cache_alloc(lnode_cache, KM_NOSLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvp = vn_alloc(KM_NOSLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (lp == NULL || nvp == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan TABLE_LOCK_EXIT(vp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* The lnode allocation may have succeeded, save it */
269473047d747f7815af570197e4ef7322d3632cEvan Yan tlp = lp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (tlp == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan tlp = kmem_cache_alloc(lnode_cache, KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (nvp == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvp = vn_alloc(KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan TABLE_LOCK_ENTER(vp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (flag != LOF_FORCE)
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp = lfind(vp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (lp != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_cache_free(lnode_cache, tlp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan vn_free(nvp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan VN_RELE(vp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto found_lnode;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp = tlp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan atomic_inc_32(&li->li_refct);
269473047d747f7815af570197e4ef7322d3632cEvan Yan vfsp = makelfsnode(vp->v_vfsp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp->lo_vnode = nvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan VN_SET_VFS_TYPE_DEV(nvp, vfsp, vp->v_type, vp->v_rdev);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvp->v_flag |= (vp->v_flag & (VNOMOUNT|VNOMAP|VDIROPEN));
269473047d747f7815af570197e4ef7322d3632cEvan Yan vn_setops(nvp, lo_vnodeops);
269473047d747f7815af570197e4ef7322d3632cEvan Yan nvp->v_data = (caddr_t)lp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp->lo_vp = vp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lp->lo_looping = 0;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lsave(lp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan vn_exists(vp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan } else {
269473047d747f7815af570197e4ef7322d3632cEvan Yan VN_RELE(vp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanfound_lnode:
269473047d747f7815af570197e4ef7322d3632cEvan Yan TABLE_LOCK_EXIT(vp, li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (ltov(lp));
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Get/Make vfs structure for given real vfs
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic struct vfs *
269473047d747f7815af570197e4ef7322d3632cEvan Yanmakelfsnode(struct vfs *vfsp, struct loinfo *li)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lfsnode *lfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lfsnode *tlfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Don't grab any locks for the fast (common) case.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (vfsp == li->li_realvfs)
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (li->li_mountvfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(li->li_refct > 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&li->li_lfslock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((lfs = lfsfind(vfsp, li)) == NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&li->li_lfslock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs = kmem_zalloc(sizeof (*lfs), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&li->li_lfslock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if ((tlfs = lfsfind(vfsp, li)) != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(lfs, sizeof (*lfs));
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs = tlfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan goto found_lfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_realvfs = vfsp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Even though the lfsnode is strictly speaking a private
269473047d747f7815af570197e4ef7322d3632cEvan Yan * implementation detail of lofs, it should behave as a regular
269473047d747f7815af570197e4ef7322d3632cEvan Yan * vfs_t for the benefit of the rest of the kernel.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan VFS_INIT(&lfs->lfs_vfs, lo_vfsops, (caddr_t)li);
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_vfs.vfs_fstype = li->li_mountvfs->vfs_fstype;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_vfs.vfs_flag =
269473047d747f7815af570197e4ef7322d3632cEvan Yan ((vfsp->vfs_flag | li->li_mflag) & ~li->li_dflag) &
269473047d747f7815af570197e4ef7322d3632cEvan Yan INHERIT_VFS_FLAG;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_vfs.vfs_bsize = vfsp->vfs_bsize;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_vfs.vfs_dev = vfsp->vfs_dev;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_vfs.vfs_fsid = vfsp->vfs_fsid;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (vfsp->vfs_mntpt != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_vfs.vfs_mntpt = vfs_getmntpoint(vfsp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan /* Leave a reference to the mountpoint */
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan (void) VFS_ROOT(vfsp, &lfs->lfs_realrootvp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * We use 1 instead of 0 as the value to associate with
269473047d747f7815af570197e4ef7322d3632cEvan Yan * an idle lfs_vfs. This is to prevent VFS_RELE()
269473047d747f7815af570197e4ef7322d3632cEvan Yan * trying to kmem_free() our lfs_t (which is the wrong
269473047d747f7815af570197e4ef7322d3632cEvan Yan * size).
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan VFS_HOLD(&lfs->lfs_vfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan lfs->lfs_next = li->li_lfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_lfs = lfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan vfs_propagate_features(vfsp, &lfs->lfs_vfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yanfound_lfs:
269473047d747f7815af570197e4ef7322d3632cEvan Yan VFS_HOLD(&lfs->lfs_vfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&li->li_lfslock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (&lfs->lfs_vfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Free lfs node since no longer in use
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanfreelfsnode(struct lfsnode *lfs, struct loinfo *li)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lfsnode *prev = NULL;
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lfsnode *this;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(MUTEX_HELD(&li->li_lfslock));
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(li->li_refct > 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (this = li->li_lfs; this != NULL; this = this->lfs_next) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (this == lfs) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(lfs->lfs_vfs.vfs_count == 1);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (prev == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_lfs = lfs->lfs_next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan else
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev->lfs_next = lfs->lfs_next;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (lfs->lfs_realrootvp != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan VN_RELE(lfs->lfs_realrootvp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (lfs->lfs_vfs.vfs_mntpt != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan refstr_rele(lfs->lfs_vfs.vfs_mntpt);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (lfs->lfs_vfs.vfs_implp != NULL) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(lfs->lfs_vfs.vfs_femhead == NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(lfs->lfs_vfs.vfs_vskap == NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(lfs->lfs_vfs.vfs_fstypevsp == NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(lfs->lfs_vfs.vfs_implp,
269473047d747f7815af570197e4ef7322d3632cEvan Yan sizeof (vfs_impl_t));
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan sema_destroy(&lfs->lfs_vfs.vfs_reflock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan kmem_free(lfs, sizeof (struct lfsnode));
269473047d747f7815af570197e4ef7322d3632cEvan Yan return;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan prev = this;
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan panic("freelfsnode");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*NOTREACHED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Find lfs given real vfs and mount instance(li)
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic struct lfsnode *
269473047d747f7815af570197e4ef7322d3632cEvan Yanlfsfind(struct vfs *vfsp, struct loinfo *li)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lfsnode *lfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(MUTEX_HELD(&li->li_lfslock));
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * We need to handle the case where a UFS filesystem was forced
269473047d747f7815af570197e4ef7322d3632cEvan Yan * unmounted and then a subsequent mount got the same vfs
269473047d747f7815af570197e4ef7322d3632cEvan Yan * structure. If the new mount lies in the lofs hierarchy, then
269473047d747f7815af570197e4ef7322d3632cEvan Yan * this will confuse lofs, because the original vfsp (of the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * forced unmounted filesystem) is still around. We check for
269473047d747f7815af570197e4ef7322d3632cEvan Yan * this condition here.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * If we find a cache vfsp hit, then we check to see if the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * cached filesystem was forced unmounted. Skip all such
269473047d747f7815af570197e4ef7322d3632cEvan Yan * entries. This should be safe to do since no
269473047d747f7815af570197e4ef7322d3632cEvan Yan * makelonode()->makelfsnode()->lfsfind() calls should be
269473047d747f7815af570197e4ef7322d3632cEvan Yan * generated for such force-unmounted filesystems (because (ufs)
269473047d747f7815af570197e4ef7322d3632cEvan Yan * lookup would've returned an error).
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (lfs = li->li_lfs; lfs != NULL; lfs = lfs->lfs_next) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (lfs->lfs_realvfs == vfsp) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct vnode *realvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan realvp = lfs->lfs_realrootvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (realvp == NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (realvp->v_vfsp == NULL || realvp->v_type == VBAD)
269473047d747f7815af570197e4ef7322d3632cEvan Yan continue;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (lfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (NULL);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Find real vfs given loopback vfs
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstruct vfs *
269473047d747f7815af570197e4ef7322d3632cEvan Yanlo_realvfs(struct vfs *vfsp, struct vnode **realrootvpp)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct loinfo *li = vtoli(vfsp);
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lfsnode *lfs;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan ASSERT(li->li_refct > 0);
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (vfsp == li->li_mountvfs) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (realrootvpp != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan *realrootvpp = vtol(li->li_rootvp)->lo_vp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (li->li_realvfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&li->li_lfslock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan for (lfs = li->li_lfs; lfs != NULL; lfs = lfs->lfs_next) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (vfsp == &lfs->lfs_vfs) {
269473047d747f7815af570197e4ef7322d3632cEvan Yan if (realrootvpp != NULL)
269473047d747f7815af570197e4ef7322d3632cEvan Yan *realrootvpp = lfs->lfs_realrootvp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&li->li_lfslock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan return (lfs->lfs_realvfs);
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan }
269473047d747f7815af570197e4ef7322d3632cEvan Yan panic("lo_realvfs");
269473047d747f7815af570197e4ef7322d3632cEvan Yan /*NOTREACHED*/
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Lnode lookup stuff.
269473047d747f7815af570197e4ef7322d3632cEvan Yan * These routines maintain a table of lnodes hashed by vp so
269473047d747f7815af570197e4ef7322d3632cEvan Yan * that the lnode for a vp can be found if it already exists.
269473047d747f7815af570197e4ef7322d3632cEvan Yan *
269473047d747f7815af570197e4ef7322d3632cEvan Yan * NB: A lofs shadow vnode causes exactly one VN_HOLD() on the
269473047d747f7815af570197e4ef7322d3632cEvan Yan * underlying vnode.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Retire old hashtables.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
269473047d747f7815af570197e4ef7322d3632cEvan Yanstatic void
269473047d747f7815af570197e4ef7322d3632cEvan Yanlretire(struct loinfo *li, struct lobucket *table, uint_t size)
269473047d747f7815af570197e4ef7322d3632cEvan Yan{
269473047d747f7815af570197e4ef7322d3632cEvan Yan struct lo_retired_ht *lrhp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan lrhp = kmem_alloc(sizeof (*lrhp), KM_SLEEP);
269473047d747f7815af570197e4ef7322d3632cEvan Yan lrhp->lrh_table = table;
269473047d747f7815af570197e4ef7322d3632cEvan Yan lrhp->lrh_size = size;
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_enter(&li->li_htlock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan lrhp->lrh_next = li->li_retired;
269473047d747f7815af570197e4ef7322d3632cEvan Yan li->li_retired = lrhp;
269473047d747f7815af570197e4ef7322d3632cEvan Yan mutex_exit(&li->li_htlock);
269473047d747f7815af570197e4ef7322d3632cEvan Yan}
269473047d747f7815af570197e4ef7322d3632cEvan Yan
269473047d747f7815af570197e4ef7322d3632cEvan Yan/*
269473047d747f7815af570197e4ef7322d3632cEvan Yan * Grow the hashtable.
269473047d747f7815af570197e4ef7322d3632cEvan Yan */
static void
lgrow(struct loinfo *li, uint_t newsize)
{
uint_t oldsize;
uint_t i;
struct lobucket *oldtable, *newtable;
/*
* It's OK to not have enough memory to resize the hashtable.
* We'll go down this path the next time we add something to the
* table, and retry the allocation then.
*/
if ((newtable = kmem_zalloc(newsize * sizeof (*li->li_hashtable),
KM_NOSLEEP)) == NULL)
return;
mutex_enter(&li->li_htlock);
if (newsize <= li->li_htsize) {
mutex_exit(&li->li_htlock);
kmem_free(newtable, newsize * sizeof (*li->li_hashtable));
return;
}
oldsize = li->li_htsize;
oldtable = li->li_hashtable;
/*
* Grab all locks so TABLE_LOCK_ENTER() calls block until the
* resize is complete.
*/
for (i = 0; i < oldsize; i++)
mutex_enter(&oldtable[i].lh_lock);
/*
* li->li_hashtable gets set before li->li_htsize, so in the
* time between the two assignments, callers of
* TABLE_LOCK_ENTER() cannot hash to a bucket beyond oldsize,
* hence we only need to grab the locks up to oldsize.
*/
for (i = 0; i < oldsize; i++)
mutex_enter(&newtable[i].lh_lock);
/*
* Rehash.
*/
for (i = 0; i < oldsize; i++) {
lnode_t *tlp, *nlp;
for (tlp = oldtable[i].lh_chain; tlp != NULL; tlp = nlp) {
uint_t hash = ltablehash(tlp->lo_vp, newsize);
nlp = tlp->lo_next;
tlp->lo_next = newtable[hash].lh_chain;
newtable[hash].lh_chain = tlp;
newtable[hash].lh_count++;
}
}
/*
* As soon as we store the new hashtable, future locking operations
* will use it. Therefore, we must ensure that all the state we've
* just established reaches global visibility before the new hashtable
* does.
*/
membar_producer();
li->li_hashtable = newtable;
/*
* table_lock_enter() relies on the fact that li->li_hashtable
* is set to its new value before li->li_htsize.
*/
membar_producer();
li->li_htsize = newsize;
/*
* The new state is consistent now, so we can drop all the locks.
*/
for (i = 0; i < oldsize; i++) {
mutex_exit(&newtable[i].lh_lock);
mutex_exit(&oldtable[i].lh_lock);
}
mutex_exit(&li->li_htlock);
lretire(li, oldtable, oldsize);
}
/*
* Put a lnode in the table
*/
static void
lsave(lnode_t *lp, struct loinfo *li)
{
ASSERT(lp->lo_vp);
ASSERT(MUTEX_HELD(TABLE_LOCK(lp->lo_vp, li)));
#ifdef LODEBUG
lo_dprint(4, "lsave lp %p hash %d\n",
lp, ltablehash(lp->lo_vp, li));
#endif
TABLE_COUNT(lp->lo_vp, li)++;
lp->lo_next = TABLE_BUCKET(lp->lo_vp, li);
TABLE_BUCKET(lp->lo_vp, li) = lp;
if (li->li_refct > (li->li_htsize << lo_resize_threshold)) {
TABLE_LOCK_EXIT(lp->lo_vp, li);
lgrow(li, li->li_htsize << lo_resize_factor);
TABLE_LOCK_ENTER(lp->lo_vp, li);
}
}
/*
* Our version of vfs_rele() that stops at 1 instead of 0, and calls
* freelfsnode() instead of kmem_free().
*/
static void
lfs_rele(struct lfsnode *lfs, struct loinfo *li)
{
vfs_t *vfsp = &lfs->lfs_vfs;
ASSERT(MUTEX_HELD(&li->li_lfslock));
ASSERT(vfsp->vfs_count > 1);
if (atomic_dec_32_nv(&vfsp->vfs_count) == 1)
freelfsnode(lfs, li);
}
/*
* Remove a lnode from the table
*/
void
freelonode(lnode_t *lp)
{
lnode_t *lt;
lnode_t *ltprev = NULL;
struct lfsnode *lfs, *nextlfs;
struct vfs *vfsp;
struct vnode *vp = ltov(lp);
struct vnode *realvp = realvp(vp);
struct loinfo *li = vtoli(vp->v_vfsp);
#ifdef LODEBUG
lo_dprint(4, "freelonode lp %p hash %d\n",
lp, ltablehash(lp->lo_vp, li));
#endif
TABLE_LOCK_ENTER(lp->lo_vp, li);
mutex_enter(&vp->v_lock);
if (vp->v_count > 1) {
vp->v_count--; /* release our hold from vn_rele */
mutex_exit(&vp->v_lock);
TABLE_LOCK_EXIT(lp->lo_vp, li);
return;
}
mutex_exit(&vp->v_lock);
for (lt = TABLE_BUCKET(lp->lo_vp, li); lt != NULL;
ltprev = lt, lt = lt->lo_next) {
if (lt == lp) {
#ifdef LODEBUG
lo_dprint(4, "freeing %p, vfsp %p\n",
vp, vp->v_vfsp);
#endif
atomic_dec_32(&li->li_refct);
vfsp = vp->v_vfsp;
vn_invalid(vp);
if (vfsp != li->li_mountvfs) {
mutex_enter(&li->li_lfslock);
/*
* Check for unused lfs
*/
lfs = li->li_lfs;
while (lfs != NULL) {
nextlfs = lfs->lfs_next;
if (vfsp == &lfs->lfs_vfs) {
lfs_rele(lfs, li);
break;
}
if (lfs->lfs_vfs.vfs_count == 1) {
/*
* Lfs is idle
*/
freelfsnode(lfs, li);
}
lfs = nextlfs;
}
mutex_exit(&li->li_lfslock);
}
if (ltprev == NULL) {
TABLE_BUCKET(lt->lo_vp, li) = lt->lo_next;
} else {
ltprev->lo_next = lt->lo_next;
}
TABLE_COUNT(lt->lo_vp, li)--;
TABLE_LOCK_EXIT(lt->lo_vp, li);
kmem_cache_free(lnode_cache, lt);
vn_free(vp);
VN_RELE(realvp);
return;
}
}
panic("freelonode");
/*NOTREACHED*/
}
/*
* Lookup a lnode by vp
*/
static lnode_t *
lfind(struct vnode *vp, struct loinfo *li)
{
lnode_t *lt;
ASSERT(MUTEX_HELD(TABLE_LOCK(vp, li)));
lt = TABLE_BUCKET(vp, li);
while (lt != NULL) {
if (lt->lo_vp == vp) {
VN_HOLD(ltov(lt));
return (lt);
}
lt = lt->lo_next;
}
return (NULL);
}
#ifdef LODEBUG
static int lofsdebug;
#endif /* LODEBUG */
/*
* Utilities used by both client and server
* Standard levels:
* 0) no debugging
* 1) hard failures
* 2) soft failures
* 3) current test software
* 4) main procedure entry points
* 5) main procedure exit points
* 6) utility procedure entry points
* 7) utility procedure exit points
* 8) obscure procedure entry points
* 9) obscure procedure exit points
* 10) random stuff
* 11) all <= 1
* 12) all <= 2
* 13) all <= 3
* ...
*/
#ifdef LODEBUG
/*VARARGS2*/
lo_dprint(level, str, a1, a2, a3, a4, a5, a6, a7, a8, a9)
int level;
char *str;
int a1, a2, a3, a4, a5, a6, a7, a8, a9;
{
if (lofsdebug == level || (lofsdebug > 10 && (lofsdebug - 10) >= level))
printf(str, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
#endif