vfs_hash.c revision 143680
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 143680 2005-03-16 07:35:06Z 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
65143561Sphkvfs_hash_get(struct mount *mp, u_int hash, int flags, struct thread *td, struct vnode **vpp)
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;
77143561Sphk			VI_LOCK(vp);
78143561Sphk			mtx_unlock(&vfs_hash_mtx);
79143561Sphk			error = vget(vp, flags | LK_INTERLOCK, td);
80143561Sphk			if (error == ENOENT)
81143561Sphk				break;
82143561Sphk			if (error)
83143561Sphk				return (error);
84143561Sphk			*vpp = vp;
85143561Sphk			return (0);
86143561Sphk		}
87143561Sphk		if (vp == NULL) {
88143561Sphk			mtx_unlock(&vfs_hash_mtx);
89143561Sphk			*vpp = NULL;
90143561Sphk			return (0);
91143561Sphk		}
92143561Sphk	}
93143561Sphk}
94143561Sphk
95143561Sphkvoid
96143561Sphkvfs_hash_remove(struct vnode *vp)
97143561Sphk{
98143561Sphk
99143561Sphk	mtx_lock(&vfs_hash_mtx);
100143561Sphk	LIST_REMOVE(vp, v_hashlist);
101143561Sphk	mtx_unlock(&vfs_hash_mtx);
102143561Sphk}
103143561Sphk
104143561Sphkint
105143561Sphkvfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, struct vnode **vpp)
106143561Sphk{
107143561Sphk	struct vnode *vp2;
108143561Sphk	int error;
109143561Sphk
110143619Sphk	lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td);
111143619Sphk	*vpp = NULL;
112143561Sphk	while (1) {
113143561Sphk		mtx_lock(&vfs_hash_mtx);
114143561Sphk		LIST_FOREACH(vp2,
115143680Sphk		    vfs_hash_index(vp->v_mount, hash), v_hashlist) {
116143561Sphk			if (vp2->v_hash != hash)
117143561Sphk				continue;
118143561Sphk			if (vp2->v_mount != vp->v_mount)
119143561Sphk				continue;
120143561Sphk			VI_LOCK(vp2);
121143561Sphk			mtx_unlock(&vfs_hash_mtx);
122143561Sphk			error = vget(vp2, flags | LK_INTERLOCK, td);
123143561Sphk			if (error == ENOENT)
124143561Sphk				break;
125143680Sphk			mtx_lock(&vfs_hash_mtx);
126143680Sphk			LIST_INSERT_HEAD(&vfs_hash_side, vp, v_hashlist);
127143680Sphk			mtx_unlock(&vfs_hash_mtx);
128143663Sphk			vput(vp);
129143663Sphk			if (!error)
130143663Sphk				*vpp = vp2;
131143663Sphk			return (error);
132143561Sphk		}
133143561Sphk		if (vp2 == NULL)
134143561Sphk			break;
135143561Sphk
136143561Sphk	}
137143561Sphk	vp->v_hash = hash;
138143680Sphk	LIST_INSERT_HEAD(vfs_hash_index(vp->v_mount, hash), vp, v_hashlist);
139143561Sphk	mtx_unlock(&vfs_hash_mtx);
140143561Sphk	return (0);
141143561Sphk}
142143561Sphk
143143561Sphkvoid
144143561Sphkvfs_hash_rehash(struct vnode *vp, u_int hash)
145143561Sphk{
146143561Sphk
147143561Sphk	mtx_lock(&vfs_hash_mtx);
148143561Sphk	LIST_REMOVE(vp, v_hashlist);
149143561Sphk	LIST_INSERT_HEAD(&vfs_hash_tbl[hash & vfs_hash_mask], vp, v_hashlist);
150143561Sphk	vp->v_hash = hash;
151143561Sphk	mtx_unlock(&vfs_hash_mtx);
152143561Sphk}
153