vfs_hash.c revision 143789
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 143789 2005-03-18 06:01:21Z phk $");
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
38143561Sphkstatic 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 */
55143561SphkSYSINIT(vfs_hash, SI_SUB_VFS, SI_ORDER_SECOND, vfs_hashinit, NULL)
56143561Sphk
57143680Sphkstatic struct vfs_hash_head *
58143680Sphkvfs_hash_index(struct mount *mp, u_int hash)
59143680Sphk{
60143680Sphk
61143680Sphk	return(&vfs_hash_tbl[(hash + mp->mnt_hashseed) & vfs_hash_mask]);
62143680Sphk}
63143680Sphk
64143561Sphkint
65143692Sphkvfs_hash_get(struct mount *mp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg)
66143561Sphk{
67143561Sphk	struct vnode *vp;
68143561Sphk	int error;
69143561Sphk
70143561Sphk	while (1) {
71143561Sphk		mtx_lock(&vfs_hash_mtx);
72143680Sphk		LIST_FOREACH(vp, vfs_hash_index(mp, hash), v_hashlist) {
73143561Sphk			if (vp->v_hash != hash)
74143561Sphk				continue;
75143561Sphk			if (vp->v_mount != mp)
76143561Sphk				continue;
77143692Sphk			if (fn != NULL && fn(vp, arg))
78143692Sphk				continue;
79143561Sphk			VI_LOCK(vp);
80143561Sphk			mtx_unlock(&vfs_hash_mtx);
81143561Sphk			error = vget(vp, flags | LK_INTERLOCK, td);
82143561Sphk			if (error == ENOENT)
83143561Sphk				break;
84143561Sphk			if (error)
85143561Sphk				return (error);
86143561Sphk			*vpp = vp;
87143561Sphk			return (0);
88143561Sphk		}
89143561Sphk		if (vp == NULL) {
90143561Sphk			mtx_unlock(&vfs_hash_mtx);
91143561Sphk			*vpp = NULL;
92143561Sphk			return (0);
93143561Sphk		}
94143561Sphk	}
95143561Sphk}
96143561Sphk
97143561Sphkvoid
98143561Sphkvfs_hash_remove(struct vnode *vp)
99143561Sphk{
100143561Sphk
101143561Sphk	mtx_lock(&vfs_hash_mtx);
102143561Sphk	LIST_REMOVE(vp, v_hashlist);
103143561Sphk	mtx_unlock(&vfs_hash_mtx);
104143561Sphk}
105143561Sphk
106143561Sphkint
107143692Sphkvfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, struct vnode **vpp, vfs_hash_cmp_t *fn, void *arg)
108143561Sphk{
109143561Sphk	struct vnode *vp2;
110143561Sphk	int error;
111143561Sphk
112143619Sphk	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
113143619Sphk	*vpp = NULL;
114143561Sphk	while (1) {
115143561Sphk		mtx_lock(&vfs_hash_mtx);
116143561Sphk		LIST_FOREACH(vp2,
117143680Sphk		    vfs_hash_index(vp->v_mount, hash), v_hashlist) {
118143561Sphk			if (vp2->v_hash != hash)
119143561Sphk				continue;
120143561Sphk			if (vp2->v_mount != vp->v_mount)
121143561Sphk				continue;
122143789Sphk			if (fn != NULL && fn(vp2, arg))
123143692Sphk				continue;
124143561Sphk			VI_LOCK(vp2);
125143561Sphk			mtx_unlock(&vfs_hash_mtx);
126143561Sphk			error = vget(vp2, flags | LK_INTERLOCK, td);
127143561Sphk			if (error == ENOENT)
128143561Sphk				break;
129143680Sphk			mtx_lock(&vfs_hash_mtx);
130143680Sphk			LIST_INSERT_HEAD(&vfs_hash_side, vp, v_hashlist);
131143680Sphk			mtx_unlock(&vfs_hash_mtx);
132143663Sphk			vput(vp);
133143663Sphk			if (!error)
134143663Sphk				*vpp = vp2;
135143663Sphk			return (error);
136143561Sphk		}
137143561Sphk		if (vp2 == NULL)
138143561Sphk			break;
139143561Sphk
140143561Sphk	}
141143561Sphk	vp->v_hash = hash;
142143680Sphk	LIST_INSERT_HEAD(vfs_hash_index(vp->v_mount, hash), vp, v_hashlist);
143143561Sphk	mtx_unlock(&vfs_hash_mtx);
144143561Sphk	return (0);
145143561Sphk}
146143561Sphk
147143561Sphkvoid
148143561Sphkvfs_hash_rehash(struct vnode *vp, u_int hash)
149143561Sphk{
150143561Sphk
151143561Sphk	mtx_lock(&vfs_hash_mtx);
152143561Sphk	LIST_REMOVE(vp, v_hashlist);
153143561Sphk	LIST_INSERT_HEAD(&vfs_hash_tbl[hash & vfs_hash_mask], vp, v_hashlist);
154143561Sphk	vp->v_hash = hash;
155143561Sphk	mtx_unlock(&vfs_hash_mtx);
156143561Sphk}
157