xref: /netbsd-src/usr.bin/systat/bufcache.c (revision befa44380d35c8421ea2278d42e8cdaeb920d152)
1*befa4438Smrg /*	$NetBSD: bufcache.c,v 1.30 2020/03/02 09:50:12 mrg Exp $	*/
2b80f4eafSsimonb 
3b80f4eafSsimonb /*-
4b80f4eafSsimonb  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5b80f4eafSsimonb  * All rights reserved.
6b80f4eafSsimonb  *
7b80f4eafSsimonb  * This code is derived from software contributed to The NetBSD Foundation
8b80f4eafSsimonb  * by Simon Burge.
9b80f4eafSsimonb  *
10b80f4eafSsimonb  * Redistribution and use in source and binary forms, with or without
11b80f4eafSsimonb  * modification, are permitted provided that the following conditions
12b80f4eafSsimonb  * are met:
13b80f4eafSsimonb  * 1. Redistributions of source code must retain the above copyright
14b80f4eafSsimonb  *    notice, this list of conditions and the following disclaimer.
15b80f4eafSsimonb  * 2. Redistributions in binary form must reproduce the above copyright
16b80f4eafSsimonb  *    notice, this list of conditions and the following disclaimer in the
17b80f4eafSsimonb  *    documentation and/or other materials provided with the distribution.
18b80f4eafSsimonb  *
19b80f4eafSsimonb  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20b80f4eafSsimonb  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21b80f4eafSsimonb  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22b80f4eafSsimonb  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23b80f4eafSsimonb  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24b80f4eafSsimonb  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25b80f4eafSsimonb  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26b80f4eafSsimonb  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27b80f4eafSsimonb  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28b80f4eafSsimonb  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29b80f4eafSsimonb  * POSSIBILITY OF SUCH DAMAGE.
30b80f4eafSsimonb  */
31b80f4eafSsimonb 
32b80f4eafSsimonb #include <sys/cdefs.h>
33b80f4eafSsimonb #ifndef lint
34*befa4438Smrg __RCSID("$NetBSD: bufcache.c,v 1.30 2020/03/02 09:50:12 mrg Exp $");
35b80f4eafSsimonb #endif /* not lint */
36b80f4eafSsimonb 
37b80f4eafSsimonb #include <sys/param.h>
38b80f4eafSsimonb #include <sys/buf.h>
39ffdbc0ccSchs #define __EXPOSE_MOUNT
40b80f4eafSsimonb #include <sys/mount.h>
412eddffdfSsimonb #include <sys/sysctl.h>
42b80f4eafSsimonb #include <sys/vnode.h>
43b80f4eafSsimonb 
442eddffdfSsimonb #include <uvm/uvm_extern.h>
452eddffdfSsimonb 
46b80f4eafSsimonb #include <err.h>
472eddffdfSsimonb #include <errno.h>
48e38c2f36Ssimonb #include <inttypes.h>
491d86c612Ssimonb #include <math.h>
50b80f4eafSsimonb #include <stdlib.h>
512eddffdfSsimonb #include <string.h>
529042b087Smrg #include <unistd.h>
53703069c0Sad #include <stdbool.h>
54b80f4eafSsimonb 
55498839aeSpk #include <miscfs/specfs/specdev.h>
56498839aeSpk 
57b80f4eafSsimonb #include "systat.h"
58b80f4eafSsimonb #include "extern.h"
59b80f4eafSsimonb 
60b80f4eafSsimonb #define VCACHE_SIZE	50
61e38c2f36Ssimonb #define	PAGEINFO_ROWS	 5
62b80f4eafSsimonb 
63b80f4eafSsimonb struct vcache {
64b80f4eafSsimonb 	int vc_age;
65b80f4eafSsimonb 	struct vnode *vc_addr;
66b80f4eafSsimonb 	struct vnode vc_node;
67b80f4eafSsimonb };
68b80f4eafSsimonb 
69b80f4eafSsimonb struct ml_entry {
70498839aeSpk 	u_int ml_count;
71498839aeSpk 	u_long ml_size;
72498839aeSpk 	u_long ml_valid;
73b80f4eafSsimonb 	struct mount *ml_addr;
74b80f4eafSsimonb 	LIST_ENTRY(ml_entry) ml_entries;
75498839aeSpk 	struct mount ml_mount;
76b80f4eafSsimonb };
77b80f4eafSsimonb 
78b80f4eafSsimonb static struct vcache vcache[VCACHE_SIZE];
79b80f4eafSsimonb static LIST_HEAD(mount_list, ml_entry) mount_list;
80b80f4eafSsimonb 
819a3978f6Schristos static uint64_t bufmem;
8200b23860Smartin static u_int nbuf, pgwidth, kbwidth;
832eddffdfSsimonb static struct uvmexp_sysctl uvmexp;
84b80f4eafSsimonb 
85fc391547Sad static void	vc_init(void);
86fc391547Sad static void	ml_init(void);
87fc391547Sad static struct 	vnode *vc_lookup(struct vnode *);
88fc391547Sad static struct 	mount *ml_lookup(struct mount *, int, int);
891d86c612Ssimonb static void	fetchuvmexp(void);
90b80f4eafSsimonb 
91b80f4eafSsimonb 
92b80f4eafSsimonb WINDOW *
openbufcache(void)93fc391547Sad openbufcache(void)
94b80f4eafSsimonb {
95b80f4eafSsimonb 
969f46bb07Sdsl 	return (subwin(stdscr, -1, 0, 5, 0));
97b80f4eafSsimonb }
98b80f4eafSsimonb 
99b80f4eafSsimonb void
closebufcache(WINDOW * w)100fc391547Sad closebufcache(WINDOW *w)
101b80f4eafSsimonb {
102b80f4eafSsimonb 
103b80f4eafSsimonb 	if (w == NULL)
104b80f4eafSsimonb 		return;
105b80f4eafSsimonb 	wclear(w);
106b80f4eafSsimonb 	wrefresh(w);
107b80f4eafSsimonb 	delwin(w);
108b80f4eafSsimonb 	ml_init();		/* Clear out mount list */
109b80f4eafSsimonb }
110b80f4eafSsimonb 
111b80f4eafSsimonb void
labelbufcache(void)112fc391547Sad labelbufcache(void)
113b80f4eafSsimonb {
114e38c2f36Ssimonb 	int i;
115e38c2f36Ssimonb 
116e38c2f36Ssimonb 	for (i = 0; i <= PAGEINFO_ROWS; i++) {
117e38c2f36Ssimonb 		wmove(wnd, i, 0);
1181d86c612Ssimonb 		wclrtoeol(wnd);
119e38c2f36Ssimonb 	}
1205a5cdfa2Ssevan 	mvwaddstr(wnd, PAGEINFO_ROWS + 1, 0,
1215a5cdfa2Ssevan "File System          Bufs used   %   kB in use   %  Bufsize kB   %  Util %");
122b80f4eafSsimonb 	wclrtoeol(wnd);
123b80f4eafSsimonb }
124b80f4eafSsimonb 
125b80f4eafSsimonb void
showbufcache(void)126fc391547Sad showbufcache(void)
127b80f4eafSsimonb {
128b80f4eafSsimonb 	int tbuf, i, lastrow;
129498839aeSpk 	double tvalid, tsize;
130b80f4eafSsimonb 	struct ml_entry *ml;
1319a3978f6Schristos 	size_t len;
1324667eeb1Schristos 	static int mib[] = { -1, 0 };
133b80f4eafSsimonb 
1344667eeb1Schristos 	if (mib[0] == -1) {
1354667eeb1Schristos 		len = __arraycount(mib);
1364667eeb1Schristos 		if (sysctlnametomib("vm.bufmem", mib, &len) == -1)
1374667eeb1Schristos 			error("can't get \"vm.bufmem\" mib: %s",
1384667eeb1Schristos 			    strerror(errno));
1394667eeb1Schristos 	}
1409a3978f6Schristos 	len = sizeof(bufmem);
1414667eeb1Schristos 	if (sysctl(mib, 2, &bufmem, &len, NULL, 0) == -1)
1424667eeb1Schristos 		error("can't get \"vm.bufmem\": %s", strerror(errno));
143498839aeSpk 
144498839aeSpk 	mvwprintw(wnd, 0, 0,
1455c263173Schristos 	    "   %*d metadata buffers using             %*"PRIu64" kBytes of "
146e38c2f36Ssimonb 	    "memory (%2.0f%%).",
147e38c2f36Ssimonb 	    pgwidth, nbuf, kbwidth, bufmem / 1024,
148e38c2f36Ssimonb 	    ((bufmem * 100.0) + 0.5) / getpagesize() / uvmexp.npages);
149498839aeSpk 	wclrtoeol(wnd);
1502eddffdfSsimonb 	mvwprintw(wnd, 1, 0,
151e38c2f36Ssimonb 	    "   %*" PRIu64 " pages for cached file data using   %*"
152e38c2f36Ssimonb 	    PRIu64 " kBytes of memory (%2.0f%%).",
153e38c2f36Ssimonb 	    pgwidth, uvmexp.filepages,
154e38c2f36Ssimonb 	    kbwidth, uvmexp.filepages * getpagesize() / 1024,
155e38c2f36Ssimonb 	    (uvmexp.filepages * 100 + 0.5) / uvmexp.npages);
1561d86c612Ssimonb 	wclrtoeol(wnd);
1571d86c612Ssimonb 	mvwprintw(wnd, 2, 0,
158e38c2f36Ssimonb 	    "   %*" PRIu64 " pages for executables using        %*"
159e38c2f36Ssimonb 	    PRIu64 " kBytes of memory (%2.0f%%).",
160e38c2f36Ssimonb 	    pgwidth, uvmexp.execpages,
161e38c2f36Ssimonb 	    kbwidth, uvmexp.execpages * getpagesize() / 1024,
162e38c2f36Ssimonb 	    (uvmexp.execpages * 100 + 0.5) / uvmexp.npages);
163e38c2f36Ssimonb 	wclrtoeol(wnd);
164e38c2f36Ssimonb 	mvwprintw(wnd, 3, 0,
165e38c2f36Ssimonb 	    "   %*" PRIu64 " pages for anon (non-file) data     %*"
166e38c2f36Ssimonb 	    PRIu64 " kBytes of memory (%2.0f%%).",
167e38c2f36Ssimonb 	    pgwidth, uvmexp.anonpages,
168e38c2f36Ssimonb 	    kbwidth, uvmexp.anonpages * getpagesize() / 1024,
169e38c2f36Ssimonb 	    (uvmexp.anonpages * 100 + 0.5) / uvmexp.npages);
170e38c2f36Ssimonb 	wclrtoeol(wnd);
171e38c2f36Ssimonb 	mvwprintw(wnd, 4, 0,
172e38c2f36Ssimonb 	    "   %*" PRIu64 " free pages                         %*"
173e38c2f36Ssimonb 	    PRIu64 " kBytes of memory (%2.0f%%).",
174e38c2f36Ssimonb 	    pgwidth, uvmexp.free,
175e38c2f36Ssimonb 	    kbwidth, uvmexp.free * getpagesize() / 1024,
176e38c2f36Ssimonb 	    (uvmexp.free * 100 + 0.5) / uvmexp.npages);
1772eddffdfSsimonb 	wclrtoeol(wnd);
1782eddffdfSsimonb 
179498839aeSpk 	if (nbuf == 0 || bufmem == 0) {
180498839aeSpk 		wclrtobot(wnd);
181498839aeSpk 		return;
182498839aeSpk 	}
183498839aeSpk 
184498839aeSpk 	tbuf = 0;
185498839aeSpk 	tvalid = tsize = 0;
186e38c2f36Ssimonb 	lastrow = PAGEINFO_ROWS + 2;	/* Leave room for header. */
187b80f4eafSsimonb 	for (i = lastrow, ml = LIST_FIRST(&mount_list); ml != NULL;
188b80f4eafSsimonb 	    i++, ml = LIST_NEXT(ml, ml_entries)) {
189b80f4eafSsimonb 
190019733f6Sdsl 		int cnt = ml->ml_count;
191498839aeSpk 		double v = ml->ml_valid;
192498839aeSpk 		double s = ml->ml_size;
193498839aeSpk 
194b80f4eafSsimonb 		/* Display in window if enough room. */
195b80f4eafSsimonb 		if (i < getmaxy(wnd) - 2) {
196b80f4eafSsimonb 			mvwprintw(wnd, i, 0, "%-20.20s", ml->ml_addr == NULL ?
197b80f4eafSsimonb 			    "NULL" : ml->ml_mount.mnt_stat.f_mntonname);
198ef2d33cbSmrg 			wprintw(wnd,
199498839aeSpk 			    "    %6d %3d    %8ld %3.0f    %8ld %3.0f     %3.0f",
200019733f6Sdsl 			    cnt, (100 * cnt) / nbuf,
201498839aeSpk 			    (long)(v/1024), 100 * v / bufmem,
202498839aeSpk 			    (long)(s/1024), 100 * s / bufmem,
203498839aeSpk 			    100 * v / s);
204b80f4eafSsimonb 			wclrtoeol(wnd);
205b80f4eafSsimonb 			lastrow = i;
206b80f4eafSsimonb 		}
207b80f4eafSsimonb 
208b80f4eafSsimonb 		/* Update statistics. */
209019733f6Sdsl 		tbuf += cnt;
210498839aeSpk 		tvalid += v;
211498839aeSpk 		tsize += s;
212b80f4eafSsimonb 	}
213b80f4eafSsimonb 
214b80f4eafSsimonb 	wclrtobot(wnd);
215ef2d33cbSmrg 	mvwprintw(wnd, lastrow + 2, 0,
216498839aeSpk 	    "%-20s    %6d %3d    %8ld %3.0f    %8ld %3.0f     %3.0f",
217ef2d33cbSmrg 	    "Total:", tbuf, (100 * tbuf) / nbuf,
218498839aeSpk 	    (long)(tvalid/1024), 100 * tvalid / bufmem,
219498839aeSpk 	    (long)(tsize/1024), 100 * tsize / bufmem,
220498839aeSpk 	    tsize != 0 ? ((100 * tvalid) / tsize) : 0);
221b80f4eafSsimonb }
222b80f4eafSsimonb 
223b80f4eafSsimonb int
initbufcache(void)224fc391547Sad initbufcache(void)
225b80f4eafSsimonb {
2261d86c612Ssimonb 	fetchuvmexp();
2271d86c612Ssimonb 	pgwidth = (int)(floor(log10((double)uvmexp.npages)) + 1);
228e38c2f36Ssimonb 	kbwidth = (int)(floor(log10(uvmexp.npages * getpagesize() / 1024.0)) +
229e38c2f36Ssimonb 	    1);
2301d86c612Ssimonb 
231b80f4eafSsimonb 	return(1);
232b80f4eafSsimonb }
233b80f4eafSsimonb 
2341d86c612Ssimonb static void
fetchuvmexp(void)2351d86c612Ssimonb fetchuvmexp(void)
236b80f4eafSsimonb {
2371d86c612Ssimonb 	int mib[2];
2382eddffdfSsimonb 	size_t size;
239b80f4eafSsimonb 
2401d86c612Ssimonb 	/* Re-read pages used for vnodes & executables */
2412eddffdfSsimonb 	size = sizeof(uvmexp);
2422eddffdfSsimonb 	mib[0] = CTL_VM;
2432eddffdfSsimonb 	mib[1] = VM_UVMEXP2;
2442eddffdfSsimonb 	if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) {
2452eddffdfSsimonb 		error("can't get uvmexp: %s\n", strerror(errno));
2462eddffdfSsimonb 		memset(&uvmexp, 0, sizeof(uvmexp));
2472eddffdfSsimonb 	}
2481d86c612Ssimonb }
2492eddffdfSsimonb 
2501d86c612Ssimonb void
fetchbufcache(void)2511d86c612Ssimonb fetchbufcache(void)
2521d86c612Ssimonb {
253498839aeSpk 	int count;
254caea20e9Satatat 	struct buf_sysctl *bp, *buffers;
2551d86c612Ssimonb 	struct vnode *vn;
2561d86c612Ssimonb 	struct ml_entry *ml;
257caea20e9Satatat 	int mib[6];
258498839aeSpk 	size_t size;
259498839aeSpk 	int extraslop = 0;
2601d86c612Ssimonb 
261498839aeSpk 	/* Re-read pages used for vnodes & executables */
2621d86c612Ssimonb 	fetchuvmexp();
263b80f4eafSsimonb 
264b80f4eafSsimonb 	/* Initialise vnode cache and mount list. */
265b80f4eafSsimonb 	vc_init();
266b80f4eafSsimonb 	ml_init();
267b80f4eafSsimonb 
268498839aeSpk 	/* Get metadata buffers */
269498839aeSpk 	size = 0;
270498839aeSpk 	buffers = NULL;
271498839aeSpk 	mib[0] = CTL_KERN;
272498839aeSpk 	mib[1] = KERN_BUF;
273caea20e9Satatat 	mib[2] = KERN_BUF_ALL;
274caea20e9Satatat 	mib[3] = KERN_BUF_ALL;
275caea20e9Satatat 	mib[4] = (int)sizeof(struct buf_sysctl);
276caea20e9Satatat 	mib[5] = INT_MAX; /* we want them all */
277caea20e9Satatat again:
278caea20e9Satatat 	if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0) {
279498839aeSpk 		error("can't get buffers size: %s\n", strerror(errno));
280498839aeSpk 		return;
281498839aeSpk 	}
282498839aeSpk 	if (size == 0)
283498839aeSpk 		return;
284498839aeSpk 
285caea20e9Satatat 	size += extraslop * sizeof(struct buf_sysctl);
286498839aeSpk 	buffers = malloc(size);
287498839aeSpk 	if (buffers == NULL) {
288498839aeSpk 		error("can't allocate buffers: %s\n", strerror(errno));
289498839aeSpk 		return;
290498839aeSpk 	}
291caea20e9Satatat 	if (sysctl(mib, 6, buffers, &size, NULL, 0) < 0) {
292498839aeSpk 		free(buffers);
293*befa4438Smrg 		if (extraslop < 1000) {
294*befa4438Smrg 			extraslop += 100;
295498839aeSpk 			goto again;
296498839aeSpk 		}
297498839aeSpk 		error("can't get buffers: %s\n", strerror(errno));
298498839aeSpk 		return;
299498839aeSpk 	}
300498839aeSpk 
301caea20e9Satatat 	nbuf = size / sizeof(struct buf_sysctl);
302498839aeSpk 	for (bp = buffers; bp < buffers + nbuf; bp++) {
303caea20e9Satatat 		if (UINT64TOPTR(bp->b_vp) != NULL) {
304498839aeSpk 			struct mount *mp;
305caea20e9Satatat 			vn = vc_lookup(UINT64TOPTR(bp->b_vp));
306b80f4eafSsimonb 			if (vn == NULL)
3076a02b7beSchristos 				break;
308498839aeSpk 
309498839aeSpk 			mp = vn->v_mount;
310498839aeSpk 			/*
311498839aeSpk 			 * References to mounted-on vnodes should be
312498839aeSpk 			 * counted towards the mounted filesystem.
313498839aeSpk 			 */
314703069c0Sad 			if (vn->v_type == VBLK && vn->v_specnode != NULL) {
315703069c0Sad 				specnode_t sn;
316703069c0Sad 				specdev_t sd;
317703069c0Sad 				if (!KREAD(vn->v_specnode, &sn, sizeof(sn)))
318498839aeSpk 					continue;
319703069c0Sad 				if (!KREAD(sn.sn_dev, &sd, sizeof(sd)))
320703069c0Sad 					continue;
321703069c0Sad 				if (sd.sd_mountpoint)
322703069c0Sad 					mp = sd.sd_mountpoint;
323498839aeSpk 			}
324498839aeSpk 			if (mp != NULL)
3256e28978dSchristos 				(void)ml_lookup(mp, bp->b_bufsize,
326b80f4eafSsimonb 				    bp->b_bcount);
327b80f4eafSsimonb 		}
328b80f4eafSsimonb 	}
329b80f4eafSsimonb 
330b80f4eafSsimonb 	/* simple sort - there's not that many entries */
331b80f4eafSsimonb 	do {
332b80f4eafSsimonb 		if ((ml = LIST_FIRST(&mount_list)) == NULL ||
333b80f4eafSsimonb 		    LIST_NEXT(ml, ml_entries) == NULL)
334b80f4eafSsimonb 			break;
335b80f4eafSsimonb 
336b80f4eafSsimonb 		count = 0;
337b80f4eafSsimonb 		for (ml = LIST_FIRST(&mount_list); ml != NULL;
338b80f4eafSsimonb 		    ml = LIST_NEXT(ml, ml_entries)) {
339b80f4eafSsimonb 			if (LIST_NEXT(ml, ml_entries) == NULL)
340b80f4eafSsimonb 				break;
341b80f4eafSsimonb 			if (ml->ml_count < LIST_NEXT(ml, ml_entries)->ml_count) {
342b80f4eafSsimonb 				ml = LIST_NEXT(ml, ml_entries);
343b80f4eafSsimonb 				LIST_REMOVE(ml, ml_entries);
344b80f4eafSsimonb 				LIST_INSERT_HEAD(&mount_list, ml, ml_entries);
345b80f4eafSsimonb 				count++;
346b80f4eafSsimonb 			}
347b80f4eafSsimonb 		}
348b80f4eafSsimonb 	} while (count != 0);
349498839aeSpk 
350498839aeSpk 	free(buffers);
351b80f4eafSsimonb }
352b80f4eafSsimonb 
353b80f4eafSsimonb static void
vc_init(void)354fc391547Sad vc_init(void)
355b80f4eafSsimonb {
356b80f4eafSsimonb 	int i;
357b80f4eafSsimonb 
358b80f4eafSsimonb 	/* vc_addr == NULL for unused cache entry. */
359b80f4eafSsimonb 	for (i = 0; i < VCACHE_SIZE; i++)
360b80f4eafSsimonb 		vcache[i].vc_addr = NULL;
361b80f4eafSsimonb }
362b80f4eafSsimonb 
363b80f4eafSsimonb static void
ml_init(void)364fc391547Sad ml_init(void)
365b80f4eafSsimonb {
366b80f4eafSsimonb 	struct ml_entry *ml;
367b80f4eafSsimonb 
368b80f4eafSsimonb 	/* Throw out the current mount list and start again. */
369b80f4eafSsimonb 	while ((ml = LIST_FIRST(&mount_list)) != NULL) {
370b80f4eafSsimonb 		LIST_REMOVE(ml, ml_entries);
371b80f4eafSsimonb 		free(ml);
372b80f4eafSsimonb 	}
373b80f4eafSsimonb }
374b80f4eafSsimonb 
375b80f4eafSsimonb 
376b80f4eafSsimonb static struct vnode *
vc_lookup(struct vnode * vaddr)377fc391547Sad vc_lookup(struct vnode *vaddr)
378b80f4eafSsimonb {
379b80f4eafSsimonb 	struct vnode *ret;
3806a02b7beSchristos 	size_t i, oldest;
381b80f4eafSsimonb 
382b80f4eafSsimonb 	ret = NULL;
3836a02b7beSchristos 	oldest = 0;
38400b23860Smartin 	for (i = 0; i < VCACHE_SIZE; i++) {
385b80f4eafSsimonb 		if (vcache[i].vc_addr == NULL)
386b80f4eafSsimonb 			break;
38700b23860Smartin 		vcache[i].vc_age++;
388b80f4eafSsimonb 		if (vcache[i].vc_age < vcache[oldest].vc_age)
389b80f4eafSsimonb 			oldest = i;
390b80f4eafSsimonb 		if (vcache[i].vc_addr == vaddr) {
391b80f4eafSsimonb 			vcache[i].vc_age = 0;
392b80f4eafSsimonb 			ret = &vcache[i].vc_node;
393b80f4eafSsimonb 		}
394b80f4eafSsimonb 	}
395b80f4eafSsimonb 
396b80f4eafSsimonb 	/* Find an entry in the cache? */
397b80f4eafSsimonb 	if (ret != NULL)
398b80f4eafSsimonb 		return(ret);
399b80f4eafSsimonb 
400b80f4eafSsimonb 	/* Go past the end of the cache? */
401b80f4eafSsimonb 	if  (i >= VCACHE_SIZE)
402b80f4eafSsimonb 		i = oldest;
403b80f4eafSsimonb 
404b80f4eafSsimonb 	/* Read in new vnode and reset age counter. */
4056a02b7beSchristos 	if (KREAD(vaddr, &vcache[i].vc_node, sizeof(struct vnode)) == 0)
4066a02b7beSchristos 		return NULL;
407b80f4eafSsimonb 	vcache[i].vc_addr = vaddr;
408b80f4eafSsimonb 	vcache[i].vc_age = 0;
409b80f4eafSsimonb 
410b80f4eafSsimonb 	return(&vcache[i].vc_node);
411b80f4eafSsimonb }
412b80f4eafSsimonb 
413b80f4eafSsimonb static struct mount *
ml_lookup(struct mount * maddr,int size,int valid)414fc391547Sad ml_lookup(struct mount *maddr, int size, int valid)
415b80f4eafSsimonb {
416b80f4eafSsimonb 	struct ml_entry *ml;
417b80f4eafSsimonb 
418b80f4eafSsimonb 	for (ml = LIST_FIRST(&mount_list); ml != NULL;
419b80f4eafSsimonb 	    ml = LIST_NEXT(ml, ml_entries))
420b80f4eafSsimonb 		if (ml->ml_addr == maddr) {
421b80f4eafSsimonb 			ml->ml_count++;
422498839aeSpk 			ml->ml_size += size;
423498839aeSpk 			ml->ml_valid += valid;
424b80f4eafSsimonb 			if (ml->ml_addr == NULL)
425b80f4eafSsimonb 				return(NULL);
426b80f4eafSsimonb 			else
427b80f4eafSsimonb 				return(&ml->ml_mount);
428b80f4eafSsimonb 		}
429b80f4eafSsimonb 
430850fb37fSjwise 	if ((ml = malloc(sizeof(struct ml_entry))) == NULL) {
431850fb37fSjwise 		error("out of memory");
432850fb37fSjwise 		die(0);
433850fb37fSjwise 	}
434b80f4eafSsimonb 	LIST_INSERT_HEAD(&mount_list, ml, ml_entries);
435b80f4eafSsimonb 	ml->ml_count = 1;
436498839aeSpk 	ml->ml_size = size;
437498839aeSpk 	ml->ml_valid = valid;
438b80f4eafSsimonb 	ml->ml_addr = maddr;
439b80f4eafSsimonb 	if (maddr == NULL)
440b80f4eafSsimonb 		return(NULL);
441b80f4eafSsimonb 
442b80f4eafSsimonb 	KREAD(maddr, &ml->ml_mount, sizeof(struct mount));
443b80f4eafSsimonb 	return(&ml->ml_mount);
444b80f4eafSsimonb }
445