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