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: releng/10.2/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