vfs_hash.c revision 143619
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 143619 2005-03-15 08:07:07Z phk $");
30143561Sphk
31143561Sphk#include <sys/param.h>
32143561Sphk#include <sys/systm.h>
33143561Sphk#include <sys/kernel.h>
34143561Sphk#include <sys/malloc.h>
35143561Sphk#include <sys/vnode.h>
36143561Sphk
37143561Sphkstatic MALLOC_DEFINE(M_VFS_HASH, "VFS hash", "VFS hash table");
38143561Sphk
39143561Sphkstatic LIST_HEAD(vfs_hashhead, vnode)	*vfs_hash_tbl;
40143561Sphkstatic u_long				vfs_hash_mask;
41143561Sphkstatic struct mtx			vfs_hash_mtx;
42143561Sphk
43143561Sphkstatic void
44143561Sphkvfs_hashinit(void *dummy __unused)
45143561Sphk{
46143561Sphk
47143561Sphk	vfs_hash_tbl = hashinit(desiredvnodes, M_VFS_HASH, &vfs_hash_mask);
48143561Sphk	mtx_init(&vfs_hash_mtx, "vfs hash", NULL, MTX_DEF);
49143561Sphk}
50143561Sphk
51143561Sphk/* Must be SI_ORDER_SECOND so desiredvnodes is available */
52143561SphkSYSINIT(vfs_hash, SI_SUB_VFS, SI_ORDER_SECOND, vfs_hashinit, NULL)
53143561Sphk
54143561Sphkint
55143561Sphkvfs_hash_get(struct mount *mp, u_int hash, int flags, struct thread *td, struct vnode **vpp)
56143561Sphk{
57143561Sphk	struct vnode *vp;
58143561Sphk	int error;
59143561Sphk
60143561Sphk	while (1) {
61143561Sphk		mtx_lock(&vfs_hash_mtx);
62143561Sphk		LIST_FOREACH(vp,
63143561Sphk		    &vfs_hash_tbl[hash & vfs_hash_mask], v_hashlist) {
64143561Sphk			if (vp->v_hash != hash)
65143561Sphk				continue;
66143561Sphk			if (vp->v_mount != mp)
67143561Sphk				continue;
68143561Sphk			VI_LOCK(vp);
69143561Sphk			mtx_unlock(&vfs_hash_mtx);
70143561Sphk			error = vget(vp, flags | LK_INTERLOCK, td);
71143561Sphk			if (error == ENOENT)
72143561Sphk				break;
73143561Sphk			if (error)
74143561Sphk				return (error);
75143561Sphk			*vpp = vp;
76143561Sphk			return (0);
77143561Sphk		}
78143561Sphk		if (vp == NULL) {
79143561Sphk			mtx_unlock(&vfs_hash_mtx);
80143561Sphk			*vpp = NULL;
81143561Sphk			return (0);
82143561Sphk		}
83143561Sphk	}
84143561Sphk}
85143561Sphk
86143561Sphkvoid
87143561Sphkvfs_hash_remove(struct vnode *vp)
88143561Sphk{
89143561Sphk
90143561Sphk	mtx_lock(&vfs_hash_mtx);
91143561Sphk	VI_LOCK(vp);
92143561Sphk	VNASSERT(vp->v_iflag & VI_HASHED, vp, ("vfs_hash_remove: not hashed"));
93143561Sphk	LIST_REMOVE(vp, v_hashlist);
94143561Sphk	vp->v_iflag &= ~VI_HASHED;
95143561Sphk	VI_UNLOCK(vp);
96143561Sphk	mtx_unlock(&vfs_hash_mtx);
97143561Sphk}
98143561Sphk
99143561Sphkint
100143561Sphkvfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, struct vnode **vpp)
101143561Sphk{
102143561Sphk	struct vnode *vp2;
103143561Sphk	int error;
104143561Sphk
105143619Sphk	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
106143619Sphk	*vpp = NULL;
107143561Sphk	while (1) {
108143561Sphk		mtx_lock(&vfs_hash_mtx);
109143561Sphk		LIST_FOREACH(vp2,
110143561Sphk		    &vfs_hash_tbl[hash & vfs_hash_mask], v_hashlist) {
111143561Sphk			if (vp2->v_hash != hash)
112143561Sphk				continue;
113143561Sphk			if (vp2->v_mount != vp->v_mount)
114143561Sphk				continue;
115143561Sphk			VI_LOCK(vp2);
116143561Sphk			mtx_unlock(&vfs_hash_mtx);
117143561Sphk			error = vget(vp2, flags | LK_INTERLOCK, td);
118143561Sphk			if (error == ENOENT)
119143561Sphk				break;
120143561Sphk			if (error)
121143561Sphk				return (error);
122143561Sphk			*vpp = vp2;
123143561Sphk			return (0);
124143561Sphk		}
125143561Sphk		if (vp2 == NULL)
126143561Sphk			break;
127143561Sphk
128143561Sphk	}
129143561Sphk	VI_LOCK(vp);
130143561Sphk	VNASSERT(!(vp->v_iflag & VI_HASHED), vp,
131143561Sphk	    ("vfs_hash_insert: already hashed"));
132143561Sphk	vp->v_hash = hash;
133143561Sphk	LIST_INSERT_HEAD(&vfs_hash_tbl[hash & vfs_hash_mask], vp, v_hashlist);
134143561Sphk	vp->v_iflag |= VI_HASHED;
135143561Sphk	VI_UNLOCK(vp);
136143561Sphk	mtx_unlock(&vfs_hash_mtx);
137143561Sphk	return (0);
138143561Sphk}
139143561Sphk
140143561Sphkvoid
141143561Sphkvfs_hash_rehash(struct vnode *vp, u_int hash)
142143561Sphk{
143143561Sphk
144143561Sphk	mtx_lock(&vfs_hash_mtx);
145143561Sphk	VNASSERT(vp->v_iflag & VI_HASHED, vp, ("vfs_hash_rehash: not hashed"));
146143561Sphk	LIST_REMOVE(vp, v_hashlist);
147143561Sphk	LIST_INSERT_HEAD(&vfs_hash_tbl[hash & vfs_hash_mask], vp, v_hashlist);
148143561Sphk	vp->v_hash = hash;
149143561Sphk	mtx_unlock(&vfs_hash_mtx);
150143561Sphk}
151