vnode.c revision 1.16.8.1 1 /* $NetBSD: vnode.c,v 1.16.8.1 2024/06/29 19:43:25 perseant Exp $ */
2 /*-
3 * Copyright (c) 2003 The NetBSD Foundation, Inc.
4 * All rights reserved.
5 *
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Konrad E. Schroder <perseant (at) hhhh.org>.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/time.h>
34 #include <sys/buf.h>
35 #include <sys/mount.h>
36 #include <sys/queue.h>
37
38 #define VU_DIROP 0x01000000 /* XXX XXX from sys/vnode.h */
39 #define vnode uvnode
40 #include <ufs/lfs/lfs.h>
41 #include <ufs/lfs/lfs_inode.h>
42 #undef vnode
43
44 #include <assert.h>
45 #include <err.h>
46 #include <errno.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 #include <util.h>
53
54 #include "bufcache.h"
55 #include "extern.h"
56 #include "kernelops.h"
57
58 struct uvnodetq vnodetq;
59 struct uvnodelst getvnodelist[VNODE_HASH_MAX];
60 struct vgrlst vgrlist;
61
62 int nvnodes;
63
64 /* Convert between inode pointers and vnode pointers. */
65 #ifndef VTOI
66 #define VTOI(vp) ((struct inode *)(vp)->v_data)
67 #endif
68
69 /*
70 * Raw device uvnode ops
71 */
72
73 int
74 raw_vop_strategy(struct ubuf * bp)
75 {
76 if (bp->b_flags & B_READ) {
77 if (kops.ko_pread(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
78 bp->b_blkno * dev_bsize) < bp->b_bcount)
79 return errno;
80 return 0;
81 } else {
82 return kops.ko_pwrite(bp->b_vp->v_fd, bp->b_data, bp->b_bcount,
83 bp->b_blkno * dev_bsize);
84 }
85 }
86
87 int
88 raw_vop_bwrite(struct ubuf * bp)
89 {
90 bp->b_flags &= ~(B_READ | B_DELWRI | B_DONE | B_ERROR);
91 raw_vop_strategy(bp);
92 brelse(bp, 0);
93 return 0;
94 }
95
96 int
97 raw_vop_bmap(struct uvnode * vp, daddr_t lbn, daddr_t * daddrp)
98 {
99 *daddrp = lbn;
100 return 0;
101 }
102
103 /* Register fs-specific vnode create and destroy functions */
104 void
105 register_vget(void *fs, struct uvnode *getfunc(void *, ino_t, void *),
106 int freefunc(struct uvnode *))
107 {
108 struct vget_reg *vgr;
109
110 vgr = emalloc(sizeof(*vgr));
111 vgr->vgr_fs = fs;
112 vgr->vgr_getfunc = getfunc;
113 vgr->vgr_freefunc = freefunc;
114 LIST_INSERT_HEAD(&vgrlist, vgr, vgr_list);
115 }
116
117 static struct uvnode *
118 VFS_VGET(void *fs, ino_t ino, void *arg)
119 {
120 struct vget_reg *vgr;
121 struct uvnode *vp;
122 int hash;
123
124 LIST_FOREACH(vgr, &vgrlist, vgr_list) {
125 if (vgr->vgr_fs == fs) {
126 vp = vgr->vgr_getfunc(fs, ino, arg);
127 ++nvnodes;
128 hash = ((int)(intptr_t)fs + ino) & (VNODE_HASH_MAX - 1);
129 LIST_INSERT_HEAD(&getvnodelist[hash], vp, v_getvnodes);
130 TAILQ_INSERT_HEAD(&vnodetq, vp, v_mntvnodes);
131 return vp;
132 }
133 }
134 return NULL;
135 }
136
137 void
138 vnode_destroy(struct uvnode *tossvp)
139 {
140 struct vget_reg *vgr;
141 struct ubuf *bp;
142
143 --nvnodes;
144 LIST_REMOVE(tossvp, v_getvnodes);
145 TAILQ_REMOVE(&vnodetq, tossvp, v_mntvnodes);
146 while ((bp = LIST_FIRST(&tossvp->v_dirtyblkhd)) != NULL) {
147 LIST_REMOVE(bp, b_vnbufs);
148 bremfree(bp);
149 buf_destroy(bp);
150 }
151 while ((bp = LIST_FIRST(&tossvp->v_cleanblkhd)) != NULL) {
152 LIST_REMOVE(bp, b_vnbufs);
153 bremfree(bp);
154 buf_destroy(bp);
155 }
156 LIST_FOREACH(vgr, &vgrlist, vgr_list) {
157 if (vgr->vgr_fs == tossvp->v_fs) {
158 if (vgr->vgr_freefunc == NULL
159 || vgr->vgr_freefunc(tossvp) == 0) {
160 free(tossvp->v_data);
161 }
162 break;
163 }
164 }
165 memset(tossvp, 0, sizeof(*tossvp));
166 free(tossvp);
167 }
168
169 int hits, misses;
170
171 /*
172 * Find a vnode in the cache; if not present, get it from the
173 * filesystem-specific vget routine.
174 */
175 struct uvnode *
176 vget(void *fs, ino_t ino)
177 {
178 return vget3(fs, ino, NULL);
179 }
180
181 struct uvnode *
182 vget3(void *fs, ino_t ino, void *arg)
183 {
184 struct uvnode *vp, *tossvp;
185 int hash;
186
187 /* Look in the uvnode cache */
188 hash = ((unsigned long)fs + ino) & (VNODE_HASH_MAX - 1);
189 LIST_FOREACH(vp, &getvnodelist[hash], v_getvnodes) {
190 if (vp->v_fs != fs)
191 continue;
192 if (VTOI(vp)->i_number == ino) {
193 /* Move to the front of both lists */
194 LIST_REMOVE(vp, v_getvnodes);
195 LIST_INSERT_HEAD(&getvnodelist[hash], vp, v_getvnodes);
196 TAILQ_REMOVE(&vnodetq, vp, v_mntvnodes);
197 TAILQ_INSERT_HEAD(&vnodetq, vp, v_mntvnodes);
198 ++hits;
199 break;
200 }
201 }
202
203 /* Don't let vnode list grow arbitrarily */
204 while (nvnodes > VNODE_CACHE_SIZE) {
205 TAILQ_FOREACH_REVERSE(tossvp, &vnodetq, uvnodetq, v_mntvnodes) {
206 if (LIST_EMPTY(&tossvp->v_dirtyblkhd) &&
207 tossvp->v_usecount == 0 &&
208 !(tossvp->v_uflag & VU_DIROP)) {
209 vnode_destroy(tossvp);
210 break;
211 }
212 }
213 if (tossvp == NULL)
214 break;
215 }
216
217 if (vp)
218 return vp;
219
220 ++misses;
221 return VFS_VGET(fs, ino, arg);
222 }
223
224 void
225 vref(struct uvnode *vp)
226 {
227 ++vp->v_usecount;
228 }
229
230 void
231 vrele(struct uvnode *vp)
232 {
233 --vp->v_usecount;
234 }
235
236 void
237 vfs_init(void)
238 {
239 int i;
240
241 nvnodes = 0;
242 TAILQ_INIT(&vnodetq);
243 for (i = 0; i < VNODE_HASH_MAX; i++)
244 LIST_INIT(&getvnodelist[i]);
245 LIST_INIT(&vgrlist);
246 }
247