vfs_hash.c revision 245406
1143561Sphk/*- 2143561Sphk * Copyright (c) 2005 Poul-Henning Kamp 3143561Sphk * All rights reserved. 4143561Sphk * 5143561Sphk * Redistribution and use in source and binary forms, with or without 6143561Sphk * modification, are permitted provided that the following conditions 7143561Sphk * are met: 8143561Sphk * 1. Redistributions of source code must retain the above copyright 9143561Sphk * notice, this list of conditions and the following disclaimer. 10143561Sphk * 2. Redistributions in binary form must reproduce the above copyright 11143561Sphk * notice, this list of conditions and the following disclaimer in the 12143561Sphk * documentation and/or other materials provided with the distribution. 13143561Sphk * 14143561Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15143561Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16143561Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17143561Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18143561Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19143561Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20143561Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21143561Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22143561Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23143561Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24143561Sphk * SUCH DAMAGE. 25143561Sphk * 26143561Sphk */ 27143561Sphk 28143561Sphk#include <sys/cdefs.h> 29143561Sphk__FBSDID("$FreeBSD: head/sys/kern/vfs_hash.c 245406 2013-01-14 05:41:40Z kib $"); 30143561Sphk 31143561Sphk#include <sys/param.h> 32143561Sphk#include <sys/systm.h> 33143561Sphk#include <sys/kernel.h> 34143561Sphk#include <sys/malloc.h> 35143680Sphk#include <sys/mount.h> 36143561Sphk#include <sys/vnode.h> 37143561Sphk 38151897Srwatsonstatic MALLOC_DEFINE(M_VFS_HASH, "vfs_hash", "VFS hash table"); 39143561Sphk 40143680Sphkstatic LIST_HEAD(vfs_hash_head, vnode) *vfs_hash_tbl; 41143680Sphkstatic LIST_HEAD(,vnode) vfs_hash_side; 42143561Sphkstatic u_long vfs_hash_mask; 43143561Sphkstatic struct mtx vfs_hash_mtx; 44143561Sphk 45143561Sphkstatic void 46143561Sphkvfs_hashinit(void *dummy __unused) 47143561Sphk{ 48143561Sphk 49143561Sphk vfs_hash_tbl = hashinit(desiredvnodes, M_VFS_HASH, &vfs_hash_mask); 50143561Sphk mtx_init(&vfs_hash_mtx, "vfs hash", NULL, MTX_DEF); 51143680Sphk LIST_INIT(&vfs_hash_side); 52143561Sphk} 53143561Sphk 54143561Sphk/* Must be SI_ORDER_SECOND so desiredvnodes is available */ 55177253SrwatsonSYSINIT(vfs_hash, SI_SUB_VFS, SI_ORDER_SECOND, vfs_hashinit, NULL); 56143561Sphk 57245406Skibu_int 58245406Skibvfs_hash_index(struct vnode *vp) 59245406Skib{ 60245406Skib 61245406Skib return (vp->v_hash + vp->v_mount->mnt_hashseed); 62245406Skib} 63245406Skib 64143680Sphkstatic struct vfs_hash_head * 65245405Skibvfs_hash_bucket(const struct mount *mp, u_int hash) 66143680Sphk{ 67143680Sphk 68245405Skib return (&vfs_hash_tbl[(hash + mp->mnt_hashseed) & vfs_hash_mask]); 69143680Sphk} 70143680Sphk 71143561Sphkint 72157832Sdelphijvfs_hash_get(const struct mount *mp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg) 73143561Sphk{ 74143561Sphk struct vnode *vp; 75143561Sphk int error; 76143561Sphk 77143561Sphk while (1) { 78143561Sphk mtx_lock(&vfs_hash_mtx); 79245405Skib LIST_FOREACH(vp, vfs_hash_bucket(mp, hash), v_hashlist) { 80143561Sphk if (vp->v_hash != hash) 81143561Sphk continue; 82143561Sphk if (vp->v_mount != mp) 83143561Sphk continue; 84143692Sphk if (fn != NULL && fn(vp, arg)) 85143692Sphk continue; 86143561Sphk VI_LOCK(vp); 87143561Sphk mtx_unlock(&vfs_hash_mtx); 88143561Sphk error = vget(vp, flags | LK_INTERLOCK, td); 89150011Stegge if (error == ENOENT && (flags & LK_NOWAIT) == 0) 90143561Sphk break; 91143561Sphk if (error) 92143561Sphk return (error); 93143561Sphk *vpp = vp; 94143561Sphk return (0); 95143561Sphk } 96143561Sphk if (vp == NULL) { 97143561Sphk mtx_unlock(&vfs_hash_mtx); 98143561Sphk *vpp = NULL; 99143561Sphk return (0); 100143561Sphk } 101143561Sphk } 102143561Sphk} 103143561Sphk 104143561Sphkvoid 105143561Sphkvfs_hash_remove(struct vnode *vp) 106143561Sphk{ 107143561Sphk 108143561Sphk mtx_lock(&vfs_hash_mtx); 109143561Sphk LIST_REMOVE(vp, v_hashlist); 110143561Sphk mtx_unlock(&vfs_hash_mtx); 111143561Sphk} 112143561Sphk 113143561Sphkint 114143692Sphkvfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg) 115143561Sphk{ 116143561Sphk struct vnode *vp2; 117143561Sphk int error; 118143561Sphk 119143619Sphk *vpp = NULL; 120143561Sphk while (1) { 121143561Sphk mtx_lock(&vfs_hash_mtx); 122143561Sphk LIST_FOREACH(vp2, 123245405Skib vfs_hash_bucket(vp->v_mount, hash), v_hashlist) { 124143561Sphk if (vp2->v_hash != hash) 125143561Sphk continue; 126143561Sphk if (vp2->v_mount != vp->v_mount) 127143561Sphk continue; 128143789Sphk if (fn != NULL && fn(vp2, arg)) 129143692Sphk continue; 130143561Sphk VI_LOCK(vp2); 131143561Sphk mtx_unlock(&vfs_hash_mtx); 132143561Sphk error = vget(vp2, flags | LK_INTERLOCK, td); 133150011Stegge if (error == ENOENT && (flags & LK_NOWAIT) == 0) 134143561Sphk break; 135143680Sphk mtx_lock(&vfs_hash_mtx); 136143680Sphk LIST_INSERT_HEAD(&vfs_hash_side, vp, v_hashlist); 137143680Sphk mtx_unlock(&vfs_hash_mtx); 138143663Sphk vput(vp); 139143663Sphk if (!error) 140143663Sphk *vpp = vp2; 141143663Sphk return (error); 142143561Sphk } 143143561Sphk if (vp2 == NULL) 144143561Sphk break; 145143561Sphk 146143561Sphk } 147143561Sphk vp->v_hash = hash; 148245405Skib LIST_INSERT_HEAD(vfs_hash_bucket(vp->v_mount, hash), vp, v_hashlist); 149143561Sphk mtx_unlock(&vfs_hash_mtx); 150143561Sphk return (0); 151143561Sphk} 152143561Sphk 153143561Sphkvoid 154143561Sphkvfs_hash_rehash(struct vnode *vp, u_int hash) 155143561Sphk{ 156143561Sphk 157143561Sphk mtx_lock(&vfs_hash_mtx); 158143561Sphk LIST_REMOVE(vp, v_hashlist); 159245405Skib LIST_INSERT_HEAD(vfs_hash_bucket(vp->v_mount, hash), vp, v_hashlist); 160143561Sphk vp->v_hash = hash; 161143561Sphk mtx_unlock(&vfs_hash_mtx); 162143561Sphk} 163