vfs_hash.c revision 143561
1/*-
2 * Copyright (c) 2005 Poul-Henning Kamp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/kern/vfs_hash.c 143561 2005-03-14 10:01:29Z phk $");
30
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/kernel.h>
34#include <sys/malloc.h>
35#include <sys/vnode.h>
36
37#if 0
38#include "opt_mac.h"
39
40#include <sys/bio.h>
41#include <sys/buf.h>
42#include <sys/conf.h>
43#include <sys/event.h>
44#include <sys/eventhandler.h>
45#include <sys/extattr.h>
46#include <sys/fcntl.h>
47#include <sys/kdb.h>
48#include <sys/kthread.h>
49#include <sys/mac.h>
50#include <sys/mount.h>
51#include <sys/namei.h>
52#include <sys/reboot.h>
53#include <sys/sleepqueue.h>
54#include <sys/stat.h>
55#include <sys/sysctl.h>
56#include <sys/syslog.h>
57#include <sys/vmmeter.h>
58
59#include <machine/stdarg.h>
60
61#include <vm/vm.h>
62#include <vm/vm_object.h>
63#include <vm/vm_extern.h>
64#include <vm/pmap.h>
65#include <vm/vm_map.h>
66#include <vm/vm_page.h>
67#include <vm/vm_kern.h>
68#include <vm/uma.h>
69
70#endif
71
72static MALLOC_DEFINE(M_VFS_HASH, "VFS hash", "VFS hash table");
73
74static LIST_HEAD(vfs_hashhead, vnode)	*vfs_hash_tbl;
75static u_long				vfs_hash_mask;
76static struct mtx			vfs_hash_mtx;
77
78static void
79vfs_hashinit(void *dummy __unused)
80{
81
82	vfs_hash_tbl = hashinit(desiredvnodes, M_VFS_HASH, &vfs_hash_mask);
83	mtx_init(&vfs_hash_mtx, "vfs hash", NULL, MTX_DEF);
84}
85
86/* Must be SI_ORDER_SECOND so desiredvnodes is available */
87SYSINIT(vfs_hash, SI_SUB_VFS, SI_ORDER_SECOND, vfs_hashinit, NULL)
88
89int
90vfs_hash_get(struct mount *mp, u_int hash, int flags, struct thread *td, struct vnode **vpp)
91{
92	struct vnode *vp;
93	int error;
94
95	while (1) {
96		mtx_lock(&vfs_hash_mtx);
97		LIST_FOREACH(vp,
98		    &vfs_hash_tbl[hash & vfs_hash_mask], v_hashlist) {
99			if (vp->v_hash != hash)
100				continue;
101			if (vp->v_mount != mp)
102				continue;
103			VI_LOCK(vp);
104			mtx_unlock(&vfs_hash_mtx);
105			error = vget(vp, flags | LK_INTERLOCK, td);
106			if (error == ENOENT)
107				break;
108			if (error)
109				return (error);
110			*vpp = vp;
111			return (0);
112		}
113		if (vp == NULL) {
114			mtx_unlock(&vfs_hash_mtx);
115			*vpp = NULL;
116			return (0);
117		}
118	}
119}
120
121void
122vfs_hash_remove(struct vnode *vp)
123{
124
125	mtx_lock(&vfs_hash_mtx);
126	VI_LOCK(vp);
127	VNASSERT(vp->v_iflag & VI_HASHED, vp, ("vfs_hash_remove: not hashed"));
128	LIST_REMOVE(vp, v_hashlist);
129	vp->v_iflag &= ~VI_HASHED;
130	VI_UNLOCK(vp);
131	mtx_unlock(&vfs_hash_mtx);
132}
133
134int
135vfs_hash_insert(struct vnode *vp, u_int hash, int flags, struct thread *td, struct vnode **vpp)
136{
137	struct vnode *vp2;
138	int error;
139
140	while (1) {
141		mtx_lock(&vfs_hash_mtx);
142		LIST_FOREACH(vp2,
143		    &vfs_hash_tbl[hash & vfs_hash_mask], v_hashlist) {
144			if (vp2->v_hash != hash)
145				continue;
146			if (vp2->v_mount != vp->v_mount)
147				continue;
148			VI_LOCK(vp2);
149			mtx_unlock(&vfs_hash_mtx);
150			error = vget(vp2, flags | LK_INTERLOCK, td);
151			if (error == ENOENT)
152				break;
153			if (error)
154				return (error);
155			*vpp = vp2;
156			return (0);
157		}
158		if (vp2 == NULL)
159			break;
160
161	}
162	VI_LOCK(vp);
163	VNASSERT(!(vp->v_iflag & VI_HASHED), vp,
164	    ("vfs_hash_insert: already hashed"));
165	vp->v_hash = hash;
166	LIST_INSERT_HEAD(&vfs_hash_tbl[hash & vfs_hash_mask], vp, v_hashlist);
167	vp->v_iflag |= VI_HASHED;
168	VI_UNLOCK(vp);
169	mtx_unlock(&vfs_hash_mtx);
170	*vpp = NULL;
171	return (0);
172}
173
174void
175vfs_hash_rehash(struct vnode *vp, u_int hash)
176{
177
178	mtx_lock(&vfs_hash_mtx);
179	VNASSERT(vp->v_iflag & VI_HASHED, vp, ("vfs_hash_rehash: not hashed"));
180	LIST_REMOVE(vp, v_hashlist);
181	LIST_INSERT_HEAD(&vfs_hash_tbl[hash & vfs_hash_mask], vp, v_hashlist);
182	vp->v_hash = hash;
183	mtx_unlock(&vfs_hash_mtx);
184}
185