xref: /freebsd/sys/fs/pseudofs/pseudofs_vncache.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*-
2  * Copyright (c) 2001 Dag-Erling Co�dan Sm�rgrav
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  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  *      $FreeBSD$
29  */
30 
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/lock.h>
35 #include <sys/malloc.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/sbuf.h>
39 #include <sys/sysctl.h>
40 #include <sys/vnode.h>
41 
42 #include <fs/pseudofs/pseudofs.h>
43 #include <fs/pseudofs/pseudofs_internal.h>
44 
45 static MALLOC_DEFINE(M_PFSVNCACHE, "pfs_vncache", "pseudofs vnode cache");
46 
47 static struct mtx pfs_vncache_mutex;
48 
49 struct pfs_vnode {
50 	struct vnode		*pv_vnode;
51 	struct pfs_vnode	*pv_next;
52 } *pfs_vncache;
53 
54 SYSCTL_NODE(_vfs_pfs, OID_AUTO, vncache, CTLFLAG_RW, 0,
55     "pseudofs vnode cache");
56 
57 static int pfs_vncache_hits;
58 SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, hits, CTLFLAG_RD, &pfs_vncache_hits, 0,
59     "number of cache hits since initialization");
60 
61 static int pfs_vncache_misses;
62 SYSCTL_INT(_vfs_pfs_vncache, OID_AUTO, misses, CTLFLAG_RD, &pfs_vncache_misses, 0,
63     "number of cache misses since initialization");
64 
65 extern vop_t **pfs_vnodeop_p;
66 
67 /*
68  * Initialize vnode cache
69  */
70 void
71 pfs_vncache_load(void)
72 {
73 	mtx_init(&pfs_vncache_mutex, "pseudofs_vncache", MTX_DEF);
74 }
75 
76 /*
77  * Tear down vnode cache
78  */
79 void
80 pfs_vncache_unload(void)
81 {
82 	mtx_destroy(&pfs_vncache_mutex);
83 }
84 
85 /*
86  * Allocate a vnode
87  */
88 int
89 pfs_vncache_alloc(struct mount *mp, struct vnode **vpp,
90 		  struct pfs_node *pn, pid_t pid)
91 {
92 	struct pfs_vnode *pv;
93 	struct pfs_vdata *pvd;
94 	int error;
95 
96 	/* see if the vnode is in the cache */
97 	mtx_lock(&pfs_vncache_mutex);
98 	for (pv = pfs_vncache; pv; pv = pv->pv_next) {
99 		pvd = (struct pfs_vdata *)pv->pv_vnode->v_data;
100 		if (pvd->pvd_pn == pn && pvd->pvd_pid == pid) {
101 			if (vget(pv->pv_vnode, 0, curproc) == 0) {
102 				++pfs_vncache_hits;
103 				*vpp = pv->pv_vnode;
104 				mtx_unlock(&pfs_vncache_mutex);
105 				return (0);
106 			}
107 			/* XXX if this can happen, we're in trouble */
108 			break;
109 		}
110 	}
111 	mtx_unlock(&pfs_vncache_mutex);
112 	++pfs_vncache_misses;
113 
114 	/* nope, get a new one */
115 	MALLOC(pv, struct pfs_vnode *, sizeof *pv, M_PFSVNCACHE, M_WAITOK);
116 	MALLOC(pvd, struct pfs_vdata *, sizeof *pvd, M_PFSVNCACHE, M_WAITOK);
117 	error = getnewvnode(VT_PSEUDOFS, mp, pfs_vnodeop_p, vpp);
118 	if (error)
119 		return (error);
120 	pvd->pvd_pn = pn;
121 	pvd->pvd_pid = pid;
122 	(*vpp)->v_data = pvd;
123 	switch (pn->pn_type) {
124 	case pfstype_root:
125 		(*vpp)->v_flag = VROOT;
126 #if 0
127 		printf("root vnode allocated\n");
128 #endif
129 	case pfstype_dir:
130 	case pfstype_this:
131 	case pfstype_parent:
132 	case pfstype_procdir:
133 		(*vpp)->v_type = VDIR;
134 		break;
135 	case pfstype_file:
136 		(*vpp)->v_type = VREG;
137 		break;
138 	case pfstype_symlink:
139 		(*vpp)->v_type = VLNK;
140 		break;
141 	case pfstype_none:
142 		KASSERT(0, ("pfs_vncache_alloc called for null node\n"));
143 	default:
144 		panic("%s has unexpected type: %d", pn->pn_name, pn->pn_type);
145 	}
146 	pv->pv_vnode = *vpp;
147 	mtx_lock(&pfs_vncache_mutex);
148 	pv->pv_next = pfs_vncache;
149 	pfs_vncache = pv;
150 	mtx_unlock(&pfs_vncache_mutex);
151 	return (0);
152 }
153 
154 /*
155  * Free a vnode
156  */
157 int
158 pfs_vncache_free(struct vnode *vp)
159 {
160 	struct pfs_vnode *prev, *pv;
161 	struct pfs_vdata *pvd;
162 
163 	mtx_lock(&pfs_vncache_mutex);
164 	for (prev = NULL, pv = pfs_vncache; pv; prev = pv, pv = pv->pv_next)
165 		if (pv->pv_vnode == vp)
166 			break;
167 	KASSERT(pv != NULL, ("pfs_vncache_free(): not in cache\n"));
168 	if (prev)
169 		prev->pv_next = pv->pv_next;
170 	else
171 		pfs_vncache = pv->pv_next;
172 	mtx_unlock(&pfs_vncache_mutex);
173 
174 	pvd = (struct pfs_vdata *)vp->v_data;
175 	FREE(pvd, M_PFSVNCACHE);
176 	vp->v_data = NULL;
177 	FREE(pv, M_PFSVNCACHE);
178 	return (0);
179 }
180