1139776Simp/*- 21541Srgrimes * Copyright (c) 1992, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software donated to Berkeley by 61541Srgrimes * Jan-Simon Pendry. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 4. Neither the name of the University nor the names of its contributors 171541Srgrimes * may be used to endorse or promote products derived from this software 181541Srgrimes * without specific prior written permission. 191541Srgrimes * 201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301541Srgrimes * SUCH DAMAGE. 311541Srgrimes * 3222521Sdyson * @(#)null_subr.c 8.7 (Berkeley) 5/14/95 331541Srgrimes * 3450477Speter * $FreeBSD$ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes#include <sys/param.h> 381541Srgrimes#include <sys/systm.h> 3965467Sbp#include <sys/kernel.h> 4076166Smarkm#include <sys/lock.h> 4198177Ssemenu#include <sys/mutex.h> 4276166Smarkm#include <sys/malloc.h> 4376166Smarkm#include <sys/mount.h> 4476166Smarkm#include <sys/proc.h> 451541Srgrimes#include <sys/vnode.h> 4676166Smarkm 4777031Sru#include <fs/nullfs/null.h> 481541Srgrimes 491541Srgrimes/* 501541Srgrimes * Null layer cache: 511541Srgrimes * Each cache entry holds a reference to the lower vnode 521541Srgrimes * along with a pointer to the alias vnode. When an 531541Srgrimes * entry is added the lower vnode is VREF'd. When the 541541Srgrimes * alias is removed the lower vnode is vrele'd. 551541Srgrimes */ 561541Srgrimes 57245408Skib#define NULL_NHASH(vp) (&null_node_hashtbl[vfs_hash_index(vp) & null_hash_mask]) 5865467Sbp 5960938Sjakestatic LIST_HEAD(null_node_hashhead, null_node) *null_node_hashtbl; 60245408Skibstatic struct mtx null_hashmtx; 61245408Skibstatic u_long null_hash_mask; 621541Srgrimes 63151897Srwatsonstatic MALLOC_DEFINE(M_NULLFSHASH, "nullfs_hash", "NULLFS hash table"); 64151897SrwatsonMALLOC_DEFINE(M_NULLFSNODE, "nullfs_node", "NULLFS vnode private part"); 6565467Sbp 66116469Stjrstatic struct vnode * null_hashins(struct mount *, struct null_node *); 6712595Sbde 681541Srgrimes/* 691541Srgrimes * Initialise cache headers 701541Srgrimes */ 711549Srgrimesint 7222521Sdysonnullfs_init(vfsp) 7322521Sdyson struct vfsconf *vfsp; 741541Srgrimes{ 7522521Sdyson 76245408Skib null_node_hashtbl = hashinit(desiredvnodes, M_NULLFSHASH, 77245408Skib &null_hash_mask); 7898177Ssemenu mtx_init(&null_hashmtx, "nullhs", NULL, MTX_DEF); 791549Srgrimes return (0); 801541Srgrimes} 811541Srgrimes 8265467Sbpint 8365467Sbpnullfs_uninit(vfsp) 8465467Sbp struct vfsconf *vfsp; 8565467Sbp{ 8665467Sbp 8798177Ssemenu mtx_destroy(&null_hashmtx); 88245408Skib hashdestroy(null_node_hashtbl, M_NULLFSHASH, null_hash_mask); 8965467Sbp return (0); 9065467Sbp} 9165467Sbp 921541Srgrimes/* 931541Srgrimes * Return a VREF'ed alias for lower vnode if already exists, else 0. 9466356Sbp * Lower vnode should be locked on entry and will be left locked on exit. 951541Srgrimes */ 96240285Skibstruct vnode * 97116469Stjrnull_hashget(mp, lowervp) 98116469Stjr struct mount *mp; 991541Srgrimes struct vnode *lowervp; 1001541Srgrimes{ 10122521Sdyson struct null_node_hashhead *hd; 1021541Srgrimes struct null_node *a; 1031541Srgrimes struct vnode *vp; 1041541Srgrimes 105155898Sjeff ASSERT_VOP_LOCKED(lowervp, "null_hashget"); 106155898Sjeff 1071541Srgrimes /* 1081541Srgrimes * Find hash base, and then search the (two-way) linked 1091541Srgrimes * list looking for a null_node structure which is referencing 1101541Srgrimes * the lower vnode. If found, the increment the null_node 1111541Srgrimes * reference count (but NOT the lower vnode's VREF counter). 1121541Srgrimes */ 11322521Sdyson hd = NULL_NHASH(lowervp); 11498177Ssemenu mtx_lock(&null_hashmtx); 11571999Sphk LIST_FOREACH(a, hd, null_hash) { 116116469Stjr if (a->null_lowervp == lowervp && NULLTOV(a)->v_mount == mp) { 117144904Sjeff /* 118155898Sjeff * Since we have the lower node locked the nullfs 119155898Sjeff * node can not be in the process of recycling. If 120155898Sjeff * it had been recycled before we grabed the lower 121155898Sjeff * lock it would not have been found on the hash. 122155898Sjeff */ 123177725Sjeff vp = NULLTOV(a); 124177725Sjeff vref(vp); 125177725Sjeff mtx_unlock(&null_hashmtx); 1261541Srgrimes return (vp); 1271541Srgrimes } 1281541Srgrimes } 12998177Ssemenu mtx_unlock(&null_hashmtx); 13098183Ssemenu return (NULLVP); 13198183Ssemenu} 1321541Srgrimes 13398183Ssemenu/* 13498183Ssemenu * Act like null_hashget, but add passed null_node to hash if no existing 13598183Ssemenu * node found. 13698183Ssemenu */ 13798183Ssemenustatic struct vnode * 138116469Stjrnull_hashins(mp, xp) 139116469Stjr struct mount *mp; 14098183Ssemenu struct null_node *xp; 14198183Ssemenu{ 14298183Ssemenu struct null_node_hashhead *hd; 14398183Ssemenu struct null_node *oxp; 14498183Ssemenu struct vnode *ovp; 14598183Ssemenu 14698183Ssemenu hd = NULL_NHASH(xp->null_lowervp); 14798183Ssemenu mtx_lock(&null_hashmtx); 14898183Ssemenu LIST_FOREACH(oxp, hd, null_hash) { 149116469Stjr if (oxp->null_lowervp == xp->null_lowervp && 150116469Stjr NULLTOV(oxp)->v_mount == mp) { 151155898Sjeff /* 152155898Sjeff * See null_hashget for a description of this 153155898Sjeff * operation. 154155898Sjeff */ 15598183Ssemenu ovp = NULLTOV(oxp); 156177725Sjeff vref(ovp); 157143642Sjeff mtx_unlock(&null_hashmtx); 15898183Ssemenu return (ovp); 15998183Ssemenu } 16098183Ssemenu } 16198183Ssemenu LIST_INSERT_HEAD(hd, xp, null_hash); 16298183Ssemenu mtx_unlock(&null_hashmtx); 16398183Ssemenu return (NULLVP); 1641541Srgrimes} 1651541Srgrimes 166167497Steggestatic void 167232299Skibnull_destroy_proto(struct vnode *vp, void *xp) 168167497Stegge{ 169229431Skib 170232383Skib lockmgr(&vp->v_lock, LK_EXCLUSIVE, NULL); 171232299Skib VI_LOCK(vp); 172167497Stegge vp->v_data = NULL; 173167497Stegge vp->v_vnlock = &vp->v_lock; 174167497Stegge vp->v_op = &dead_vnodeops; 175232299Skib VI_UNLOCK(vp); 176167497Stegge vgone(vp); 177167497Stegge vput(vp); 178232299Skib free(xp, M_NULLFSNODE); 179167497Stegge} 180167497Stegge 181232299Skibstatic void 182232299Skibnull_insmntque_dtr(struct vnode *vp, void *xp) 183232299Skib{ 184232299Skib 185232299Skib vput(((struct null_node *)xp)->null_lowervp); 186232299Skib null_destroy_proto(vp, xp); 187232299Skib} 188232299Skib 1891541Srgrimes/* 19098183Ssemenu * Make a new or get existing nullfs node. 19198183Ssemenu * Vp is the alias vnode, lowervp is the lower vnode. 19298183Ssemenu * 19398183Ssemenu * The lowervp assumed to be locked and having "spare" reference. This routine 19498183Ssemenu * vrele lowervp if nullfs node was taken from hash. Otherwise it "transfers" 19598183Ssemenu * the caller's "spare" reference to created nullfs vnode. 1961541Srgrimes */ 19798183Ssemenuint 19898183Ssemenunull_nodeget(mp, lowervp, vpp) 1991541Srgrimes struct mount *mp; 2001541Srgrimes struct vnode *lowervp; 2011541Srgrimes struct vnode **vpp; 2021541Srgrimes{ 2031541Srgrimes struct null_node *xp; 20498183Ssemenu struct vnode *vp; 2051541Srgrimes int error; 2061541Srgrimes 207240285Skib ASSERT_VOP_LOCKED(lowervp, "lowervp"); 208240285Skib KASSERT(lowervp->v_usecount >= 1, ("Unreferenced vnode %p", lowervp)); 209229428Skib 210240285Skib /* Lookup the hash firstly. */ 211116469Stjr *vpp = null_hashget(mp, lowervp); 21298183Ssemenu if (*vpp != NULL) { 21398183Ssemenu vrele(lowervp); 21498183Ssemenu return (0); 21598183Ssemenu } 21698183Ssemenu 21716312Sdg /* 218240285Skib * The insmntque1() call below requires the exclusive lock on 219240285Skib * the nullfs vnode. Upgrade the lock now if hash failed to 220240285Skib * provide ready to use vnode. 221240285Skib */ 222240285Skib if (VOP_ISLOCKED(lowervp) != LK_EXCLUSIVE) { 223245033Skib KASSERT((MOUNTTONULLMOUNT(mp)->nullm_flags & NULLM_CACHE) != 0, 224245004Skib ("lowervp %p is not excl locked and cache is disabled", 225245004Skib lowervp)); 226240285Skib vn_lock(lowervp, LK_UPGRADE | LK_RETRY); 227240285Skib if ((lowervp->v_iflag & VI_DOOMED) != 0) { 228240285Skib vput(lowervp); 229240285Skib return (ENOENT); 230240285Skib } 231240285Skib } 232240285Skib 233240285Skib /* 23498183Ssemenu * We do not serialize vnode creation, instead we will check for 23598183Ssemenu * duplicates later, when adding new vnode to hash. 23698183Ssemenu * Note that duplicate can only appear in hash if the lowervp is 23798183Ssemenu * locked LK_SHARED. 23816312Sdg */ 239240285Skib xp = malloc(sizeof(struct null_node), M_NULLFSNODE, M_WAITOK); 24016312Sdg 241138290Sphk error = getnewvnode("null", mp, &null_vnodeops, &vp); 24216312Sdg if (error) { 243229431Skib vput(lowervp); 244184205Sdes free(xp, M_NULLFSNODE); 2451541Srgrimes return (error); 24616312Sdg } 2471541Srgrimes 24898176Ssemenu xp->null_vnode = vp; 24998176Ssemenu xp->null_lowervp = lowervp; 250250505Skib xp->null_flags = 0; 2511541Srgrimes vp->v_type = lowervp->v_type; 2521541Srgrimes vp->v_data = xp; 25366356Sbp vp->v_vnlock = lowervp->v_vnlock; 254167497Stegge error = insmntque1(vp, mp, null_insmntque_dtr, xp); 255167497Stegge if (error != 0) 256167497Stegge return (error); 25798183Ssemenu /* 25898183Ssemenu * Atomically insert our new node into the hash or vget existing 25998183Ssemenu * if someone else has beaten us to it. 26098183Ssemenu */ 261116469Stjr *vpp = null_hashins(mp, xp); 26298183Ssemenu if (*vpp != NULL) { 26398183Ssemenu vrele(lowervp); 264232299Skib null_destroy_proto(vp, xp); 26598183Ssemenu return (0); 2661541Srgrimes } 26798183Ssemenu *vpp = vp; 2681541Srgrimes 2691541Srgrimes return (0); 2701541Srgrimes} 27128832Skato 27298183Ssemenu/* 27398183Ssemenu * Remove node from hash. 27498183Ssemenu */ 27598176Ssemenuvoid 27698176Ssemenunull_hashrem(xp) 27798176Ssemenu struct null_node *xp; 27898176Ssemenu{ 27998176Ssemenu 28098177Ssemenu mtx_lock(&null_hashmtx); 28198176Ssemenu LIST_REMOVE(xp, null_hash); 28298177Ssemenu mtx_unlock(&null_hashmtx); 28398176Ssemenu} 28498176Ssemenu 28550890Sbde#ifdef DIAGNOSTIC 28628844Skato 2871541Srgrimesstruct vnode * 2881541Srgrimesnull_checkvp(vp, fil, lno) 2891541Srgrimes struct vnode *vp; 2901541Srgrimes char *fil; 2911541Srgrimes int lno; 2921541Srgrimes{ 2931541Srgrimes struct null_node *a = VTONULL(vp); 294193173Skib 2951541Srgrimes#ifdef notyet 2961541Srgrimes /* 2971541Srgrimes * Can't do this check because vop_reclaim runs 2981541Srgrimes * with a funny vop vector. 2991541Srgrimes */ 3001541Srgrimes if (vp->v_op != null_vnodeop_p) { 3011541Srgrimes printf ("null_checkvp: on non-null-node\n"); 3021541Srgrimes panic("null_checkvp"); 303193173Skib } 3041541Srgrimes#endif 30524987Skato if (a->null_lowervp == NULLVP) { 3061541Srgrimes /* Should never happen */ 307227695Skib panic("null_checkvp %p", vp); 3081541Srgrimes } 309193173Skib VI_LOCK_FLAGS(a->null_lowervp, MTX_DUPOK); 310227695Skib if (a->null_lowervp->v_usecount < 1) 311227695Skib panic ("null with unref'ed lowervp, vp %p lvp %p", 312227695Skib vp, a->null_lowervp); 313193173Skib VI_UNLOCK(a->null_lowervp); 3141541Srgrimes#ifdef notyet 3151541Srgrimes printf("null %x/%d -> %x/%d [%s, %d]\n", 316103936Sjeff NULLTOV(a), vrefcnt(NULLTOV(a)), 317103936Sjeff a->null_lowervp, vrefcnt(a->null_lowervp), 3181541Srgrimes fil, lno); 3191541Srgrimes#endif 320193173Skib return (a->null_lowervp); 3211541Srgrimes} 3221541Srgrimes#endif 323