xref: /freebsd/lib/libkvm/kvm_getswapinfo.c (revision ae3a37ad447b0b2db2a9df8c89d009fc107a425d)
1e92324a2SMatthew Dillon /*
2e92324a2SMatthew Dillon  * Copyright (c) 1999, Matthew Dillon.  All Rights Reserved.
3ae3a37adSRobert Watson  * Copyright (c) 2001, Thomas Moestl
4e92324a2SMatthew Dillon  *
5e92324a2SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
6e92324a2SMatthew Dillon  * modification, are permitted provided under the terms of the BSD
7e92324a2SMatthew Dillon  * Copyright as found in /usr/src/COPYRIGHT in the FreeBSD source tree.
8e92324a2SMatthew Dillon  */
9e92324a2SMatthew Dillon 
10e92324a2SMatthew Dillon #ifndef lint
11e92324a2SMatthew Dillon static const char copyright[] =
12e92324a2SMatthew Dillon     "@(#) Copyright (c) 1999\n"
13e92324a2SMatthew Dillon     "Matthew Dillon.  All rights reserved.\n";
14e92324a2SMatthew Dillon #endif /* not lint */
15e92324a2SMatthew Dillon 
16e92324a2SMatthew Dillon #ifndef lint
17e92324a2SMatthew Dillon static const char rcsid[] =
187f3dea24SPeter Wemm   "$FreeBSD$";
19e92324a2SMatthew Dillon #endif /* not lint */
20e92324a2SMatthew Dillon 
21e92324a2SMatthew Dillon #include <sys/param.h>
22e92324a2SMatthew Dillon #include <sys/time.h>
23e92324a2SMatthew Dillon #include <sys/stat.h>
24e92324a2SMatthew Dillon #include <sys/conf.h>
25e92324a2SMatthew Dillon #include <sys/blist.h>
26ae3a37adSRobert Watson #include <sys/sysctl.h>
27e92324a2SMatthew Dillon 
28e92324a2SMatthew Dillon #include <err.h>
29e92324a2SMatthew Dillon #include <fcntl.h>
30e92324a2SMatthew Dillon #include <kvm.h>
31e92324a2SMatthew Dillon #include <nlist.h>
321a37aa56SDavid E. O'Brien #include <paths.h>
33e92324a2SMatthew Dillon #include <stdio.h>
34e92324a2SMatthew Dillon #include <stdlib.h>
35e92324a2SMatthew Dillon #include <string.h>
36e92324a2SMatthew Dillon #include <unistd.h>
37ae3a37adSRobert Watson #include <limits.h>
38ae3a37adSRobert Watson 
39ae3a37adSRobert Watson #include "kvm_private.h"
40e92324a2SMatthew Dillon 
41e92324a2SMatthew Dillon static struct nlist kvm_swap_nl[] = {
42e92324a2SMatthew Dillon 	{ "_swapblist" },	/* new radix swap list		*/
43e92324a2SMatthew Dillon 	{ "_swdevt" },		/* list of swap devices and sizes */
44e92324a2SMatthew Dillon 	{ "_nswdev" },		/* number of swap devices */
45e92324a2SMatthew Dillon 	{ "_dmmax" },		/* maximum size of a swap block */
46e92324a2SMatthew Dillon 	{ "" }
47e92324a2SMatthew Dillon };
48e92324a2SMatthew Dillon 
49bf0e1ee3SPeter Wemm #define NL_SWAPBLIST	0
50bf0e1ee3SPeter Wemm #define NL_SWDEVT	1
51bf0e1ee3SPeter Wemm #define NL_NSWDEV	2
52bf0e1ee3SPeter Wemm #define NL_DMMAX	3
53e92324a2SMatthew Dillon 
54e92324a2SMatthew Dillon static int kvm_swap_nl_cached = 0;
55e92324a2SMatthew Dillon static int nswdev;
56ae3a37adSRobert Watson static int unswdev;  /* number of found swap dev's */
57e92324a2SMatthew Dillon static int dmmax;
58e92324a2SMatthew Dillon 
5945908a6aSBruce Evans static void getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary,
6045908a6aSBruce Evans 			      int swap_max, int flags);
61ae3a37adSRobert Watson static int kvm_getswapinfo2(kvm_t *kd, struct kvm_swap *swap_ary,
62ae3a37adSRobert Watson 			    int swap_max, int flags);
63ae3a37adSRobert Watson static int  kvm_getswapinfo_kvm(kvm_t *, struct kvm_swap *, int, int);
64ae3a37adSRobert Watson static int  kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int);
65ae3a37adSRobert Watson static int  nlist_init(kvm_t *);
66ae3a37adSRobert Watson static int  getsysctl(kvm_t *, char *, void *, int);
67ae3a37adSRobert Watson static int  getsysctl2(kvm_t *, char *, char *,  char *, int, void *, int);
68ae3a37adSRobert Watson 
69e92324a2SMatthew Dillon 
70e92324a2SMatthew Dillon #define	SVAR(var) __STRING(var)	/* to force expansion */
71e92324a2SMatthew Dillon #define	KGET(idx, var)							\
72e92324a2SMatthew Dillon 	KGET1(idx, &var, sizeof(var), SVAR(var))
73e92324a2SMatthew Dillon #define	KGET1(idx, p, s, msg)						\
74e92324a2SMatthew Dillon 	KGET2(kvm_swap_nl[idx].n_value, p, s, msg)
75e92324a2SMatthew Dillon #define	KGET2(addr, p, s, msg)						\
76e92324a2SMatthew Dillon 	if (kvm_read(kd, (u_long)(addr), p, s) != s)			\
77e92324a2SMatthew Dillon 		warnx("cannot read %s: %s", msg, kvm_geterr(kd))
78e92324a2SMatthew Dillon #define	KGETN(idx, var)							\
79e92324a2SMatthew Dillon 	KGET1N(idx, &var, sizeof(var), SVAR(var))
80e92324a2SMatthew Dillon #define	KGET1N(idx, p, s, msg)						\
81e92324a2SMatthew Dillon 	KGET2N(kvm_swap_nl[idx].n_value, p, s, msg)
82e92324a2SMatthew Dillon #define	KGET2N(addr, p, s, msg)						\
83e92324a2SMatthew Dillon 	((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0)
84e92324a2SMatthew Dillon #define	KGETRET(addr, p, s, msg)					\
85e92324a2SMatthew Dillon 	if (kvm_read(kd, (u_long)(addr), p, s) != s) {			\
86e92324a2SMatthew Dillon 		warnx("cannot read %s: %s", msg, kvm_geterr(kd));	\
87e92324a2SMatthew Dillon 		return (0);						\
88e92324a2SMatthew Dillon 	}
89e92324a2SMatthew Dillon 
90ae3a37adSRobert Watson #define GETSWDEVNAME(dev, str, flags)                                   \
91ae3a37adSRobert Watson         if (dev == NODEV) {                                             \
92ae3a37adSRobert Watson 	        strlcpy(str, "[NFS swap]", sizeof(str));                \
93ae3a37adSRobert Watson 	} else {                                                        \
94ae3a37adSRobert Watson 		snprintf(                                               \
95ae3a37adSRobert Watson                     str, sizeof(str),"%s%s",                            \
96ae3a37adSRobert Watson 		    ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""),       \
97ae3a37adSRobert Watson 		    devname(dev, S_IFCHR)                               \
98ae3a37adSRobert Watson 		);                                                      \
99ae3a37adSRobert Watson 	}
100ae3a37adSRobert Watson 
101e92324a2SMatthew Dillon int
102e92324a2SMatthew Dillon kvm_getswapinfo(
103e92324a2SMatthew Dillon 	kvm_t *kd,
104e92324a2SMatthew Dillon 	struct kvm_swap *swap_ary,
105e92324a2SMatthew Dillon 	int swap_max,
106e92324a2SMatthew Dillon 	int flags
107e92324a2SMatthew Dillon ) {
108ae3a37adSRobert Watson 	int rv;
109ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO
110ae3a37adSRobert Watson 	int i;
111ae3a37adSRobert Watson #endif
112e92324a2SMatthew Dillon 
113e92324a2SMatthew Dillon 	/*
114e92324a2SMatthew Dillon 	 * clear cache
115e92324a2SMatthew Dillon 	 */
116e92324a2SMatthew Dillon 	if (kd == NULL) {
117e92324a2SMatthew Dillon 		kvm_swap_nl_cached = 0;
118e92324a2SMatthew Dillon 		return(0);
119e92324a2SMatthew Dillon 	}
120e92324a2SMatthew Dillon 
121ae3a37adSRobert Watson 	rv = kvm_getswapinfo2(kd, swap_ary, swap_max, flags);
122ae3a37adSRobert Watson 
123ae3a37adSRobert Watson 	/* This is only called when the tree shall be dumped. It needs kvm. */
124ae3a37adSRobert Watson 	if (flags & SWIF_DUMP_TREE) {
125ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO
126ae3a37adSRobert Watson 		/*
127ae3a37adSRobert Watson 		 * sanity check: Sizes must be equal - used field must be
128ae3a37adSRobert Watson 		 * 0 after this. Fill it with total-used before, where
129ae3a37adSRobert Watson 		 * getswapinfo_radix will subtrat total-used.
130ae3a37adSRobert Watson 		 * This will of course only work if there is no swap activity
131ae3a37adSRobert Watson 		 * while we are working, so this code is normally not active.
132ae3a37adSRobert Watson 		 */
133ae3a37adSRobert Watson 		for (i = 0; i < unswdev; i++) {
134ae3a37adSRobert Watson 			swap_ary[i].ksw_used =  swap_ary[i].ksw_total -
135ae3a37adSRobert Watson 			    swap_ary[i].ksw_used;
136ae3a37adSRobert Watson 		}
137ae3a37adSRobert Watson #endif
138ae3a37adSRobert Watson 		getswapinfo_radix(kd, swap_ary, swap_max, flags);
139ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO
140ae3a37adSRobert Watson 		for (i = 0; i < unswdev; i++) {
141ae3a37adSRobert Watson 			if (swap_ary[i].ksw_used != 0) {
142ae3a37adSRobert Watson 				fprintf(stderr, "kvm_getswapinfo: swap size "
143ae3a37adSRobert Watson 				    "mismatch (%d blocks)!\n",
144ae3a37adSRobert Watson 				    swap_ary[i].ksw_used
145ae3a37adSRobert Watson 				);
146ae3a37adSRobert Watson 			}
147ae3a37adSRobert Watson 		}
148ae3a37adSRobert Watson 		/* This is fast enough now, so just do it again. */
149ae3a37adSRobert Watson 		rv = kvm_getswapinfo2(kd, swap_ary, swap_max, flags);
150ae3a37adSRobert Watson #endif
151ae3a37adSRobert Watson 	}
152ae3a37adSRobert Watson 
153ae3a37adSRobert Watson 	return rv;
154ae3a37adSRobert Watson }
155ae3a37adSRobert Watson 
156ae3a37adSRobert Watson static int
157ae3a37adSRobert Watson kvm_getswapinfo2(
158ae3a37adSRobert Watson 	kvm_t *kd,
159ae3a37adSRobert Watson 	struct kvm_swap *swap_ary,
160ae3a37adSRobert Watson 	int swap_max,
161ae3a37adSRobert Watson 	int flags
162ae3a37adSRobert Watson ) {
163ae3a37adSRobert Watson 	if (ISALIVE(kd)) {
164ae3a37adSRobert Watson 		return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags);
165ae3a37adSRobert Watson 	} else {
166ae3a37adSRobert Watson 		return kvm_getswapinfo_kvm(kd, swap_ary, swap_max, flags);
167ae3a37adSRobert Watson 	}
168ae3a37adSRobert Watson }
169ae3a37adSRobert Watson 
170ae3a37adSRobert Watson int
171ae3a37adSRobert Watson kvm_getswapinfo_kvm(
172ae3a37adSRobert Watson 	kvm_t *kd,
173ae3a37adSRobert Watson 	struct kvm_swap *swap_ary,
174ae3a37adSRobert Watson 	int swap_max,
175ae3a37adSRobert Watson 	int flags
176ae3a37adSRobert Watson ) {
177ae3a37adSRobert Watson 	int ti = 0;
178ae3a37adSRobert Watson 
179e92324a2SMatthew Dillon 	/*
180e92324a2SMatthew Dillon 	 * namelist
181e92324a2SMatthew Dillon 	 */
182ae3a37adSRobert Watson 	if (!nlist_init(kd))
183e92324a2SMatthew Dillon 		return (-1);
184e92324a2SMatthew Dillon 
185e92324a2SMatthew Dillon 	{
186e92324a2SMatthew Dillon 		struct swdevt *sw;
187e92324a2SMatthew Dillon 		int i;
188e92324a2SMatthew Dillon 
189e92324a2SMatthew Dillon 		ti = unswdev;
190e92324a2SMatthew Dillon 		if (ti >= swap_max)
191e92324a2SMatthew Dillon 			ti = swap_max - 1;
192e92324a2SMatthew Dillon 
193e92324a2SMatthew Dillon 		if (ti >= 0)
194e92324a2SMatthew Dillon 			bzero(swap_ary, sizeof(struct kvm_swap) * (ti + 1));
195e92324a2SMatthew Dillon 
196e92324a2SMatthew Dillon 		KGET(NL_SWDEVT, sw);
197e92324a2SMatthew Dillon 		for (i = 0; i < unswdev; ++i) {
198e92324a2SMatthew Dillon 			struct swdevt swinfo;
199e92324a2SMatthew Dillon 			int ttl;
200e92324a2SMatthew Dillon 
201e92324a2SMatthew Dillon 			KGET2(&sw[i], &swinfo, sizeof(swinfo), "swinfo");
202e92324a2SMatthew Dillon 
203e92324a2SMatthew Dillon 			/*
204e92324a2SMatthew Dillon 			 * old style: everything in DEV_BSIZE'd chunks,
205e92324a2SMatthew Dillon 			 * convert to pages.
206e92324a2SMatthew Dillon 			 *
207e92324a2SMatthew Dillon 			 * new style: swinfo in DEV_BSIZE'd chunks but dmmax
208e92324a2SMatthew Dillon 			 * in pages.
209bd54ec1eSDmitrij Tejblum 			 *
210bd54ec1eSDmitrij Tejblum 			 * The first dmmax is never allocating to avoid
211bd54ec1eSDmitrij Tejblum 			 * trashing the disklabels
212e92324a2SMatthew Dillon 			 */
213e92324a2SMatthew Dillon 
214bd54ec1eSDmitrij Tejblum 			ttl = swinfo.sw_nblks - dmmax;
215e92324a2SMatthew Dillon 
216e92324a2SMatthew Dillon 			if (ttl == 0)
217e92324a2SMatthew Dillon 				continue;
218e92324a2SMatthew Dillon 
219e92324a2SMatthew Dillon 			if (i < ti) {
220e92324a2SMatthew Dillon 				swap_ary[i].ksw_total = ttl;
221ae3a37adSRobert Watson 				swap_ary[i].ksw_used = swinfo.sw_used;
222e92324a2SMatthew Dillon 				swap_ary[i].ksw_flags = swinfo.sw_flags;
223ae3a37adSRobert Watson 				GETSWDEVNAME(swinfo.sw_dev,
224ae3a37adSRobert Watson 				    swap_ary[i].ksw_devname, flags
225e92324a2SMatthew Dillon 				);
226e92324a2SMatthew Dillon 			}
227e92324a2SMatthew Dillon 			if (ti >= 0) {
228e92324a2SMatthew Dillon 				swap_ary[ti].ksw_total += ttl;
229ae3a37adSRobert Watson 				swap_ary[ti].ksw_used += swinfo.sw_used;
230e92324a2SMatthew Dillon 			}
231e92324a2SMatthew Dillon 		}
232e92324a2SMatthew Dillon 	}
233e92324a2SMatthew Dillon 
234e92324a2SMatthew Dillon 	return(ti);
235e92324a2SMatthew Dillon }
236e92324a2SMatthew Dillon 
237e92324a2SMatthew Dillon /*
238e92324a2SMatthew Dillon  * scanradix() - support routine for radix scanner
239e92324a2SMatthew Dillon  */
240e92324a2SMatthew Dillon 
241e92324a2SMatthew Dillon #define TABME	tab, tab, ""
242e92324a2SMatthew Dillon 
243e92324a2SMatthew Dillon static int
244e92324a2SMatthew Dillon scanradix(
245e92324a2SMatthew Dillon 	blmeta_t *scan,
246e92324a2SMatthew Dillon 	daddr_t blk,
247e92324a2SMatthew Dillon 	daddr_t radix,
248e92324a2SMatthew Dillon 	daddr_t skip,
249e92324a2SMatthew Dillon 	daddr_t count,
250e92324a2SMatthew Dillon 	kvm_t *kd,
251e92324a2SMatthew Dillon 	int dmmax,
252e92324a2SMatthew Dillon 	int nswdev,
25345908a6aSBruce Evans 	struct kvm_swap *swap_ary,
254e92324a2SMatthew Dillon 	int swap_max,
255e92324a2SMatthew Dillon 	int tab,
256e92324a2SMatthew Dillon 	int flags
257e92324a2SMatthew Dillon ) {
258e92324a2SMatthew Dillon 	blmeta_t meta;
259ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO
260e92324a2SMatthew Dillon 	int ti = (unswdev >= swap_max) ? swap_max - 1 : unswdev;
261ae3a37adSRobert Watson #endif
262e92324a2SMatthew Dillon 
263e92324a2SMatthew Dillon 	KGET2(scan, &meta, sizeof(meta), "blmeta_t");
264e92324a2SMatthew Dillon 
265e92324a2SMatthew Dillon 	/*
266e92324a2SMatthew Dillon 	 * Terminator
267e92324a2SMatthew Dillon 	 */
268e92324a2SMatthew Dillon 	if (meta.bm_bighint == (daddr_t)-1) {
269e92324a2SMatthew Dillon 		if (flags & SWIF_DUMP_TREE) {
270e92324a2SMatthew Dillon 			printf("%*.*s(0x%06x,%d) Terminator\n",
271e92324a2SMatthew Dillon 			    TABME,
272e92324a2SMatthew Dillon 			    blk,
273e92324a2SMatthew Dillon 			    radix
274e92324a2SMatthew Dillon 			);
275e92324a2SMatthew Dillon 		}
276e92324a2SMatthew Dillon 		return(-1);
277e92324a2SMatthew Dillon 	}
278e92324a2SMatthew Dillon 
279e92324a2SMatthew Dillon 	if (radix == BLIST_BMAP_RADIX) {
280e92324a2SMatthew Dillon 		/*
281e92324a2SMatthew Dillon 		 * Leaf bitmap
282e92324a2SMatthew Dillon 		 */
283ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO
284e92324a2SMatthew Dillon 		int i;
285ae3a37adSRobert Watson #endif
286e92324a2SMatthew Dillon 
287e92324a2SMatthew Dillon 		if (flags & SWIF_DUMP_TREE) {
288e92324a2SMatthew Dillon 			printf("%*.*s(0x%06x,%d) Bitmap %08x big=%d\n",
289e92324a2SMatthew Dillon 			    TABME,
290e92324a2SMatthew Dillon 			    blk,
291e92324a2SMatthew Dillon 			    radix,
292e92324a2SMatthew Dillon 			    (int)meta.u.bmu_bitmap,
293e92324a2SMatthew Dillon 			    meta.bm_bighint
294e92324a2SMatthew Dillon 			);
295e92324a2SMatthew Dillon 		}
296e92324a2SMatthew Dillon 
297ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO
298e92324a2SMatthew Dillon 		/*
299e92324a2SMatthew Dillon 		 * If not all allocated, count.
300e92324a2SMatthew Dillon 		 */
301e92324a2SMatthew Dillon 		if (meta.u.bmu_bitmap != 0) {
302e92324a2SMatthew Dillon 			for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) {
303e92324a2SMatthew Dillon 				/*
304e92324a2SMatthew Dillon 				 * A 0 bit means allocated
305e92324a2SMatthew Dillon 				 */
306e92324a2SMatthew Dillon 				if ((meta.u.bmu_bitmap & (1 << i))) {
307e92324a2SMatthew Dillon 					int t = 0;
308e92324a2SMatthew Dillon 
309e92324a2SMatthew Dillon 					if (nswdev)
310e92324a2SMatthew Dillon 						t = (blk + i) / dmmax % nswdev;
311e92324a2SMatthew Dillon 					if (t < ti)
312e92324a2SMatthew Dillon 						--swap_ary[t].ksw_used;
313e92324a2SMatthew Dillon 					if (ti >= 0)
314e92324a2SMatthew Dillon 						--swap_ary[ti].ksw_used;
315e92324a2SMatthew Dillon 				}
316e92324a2SMatthew Dillon 			}
317e92324a2SMatthew Dillon 		}
318ae3a37adSRobert Watson #endif
319e92324a2SMatthew Dillon 	} else if (meta.u.bmu_avail == radix) {
320e92324a2SMatthew Dillon 		/*
321e92324a2SMatthew Dillon 		 * Meta node if all free
322e92324a2SMatthew Dillon 		 */
323e92324a2SMatthew Dillon 		if (flags & SWIF_DUMP_TREE) {
324e92324a2SMatthew Dillon 			printf("%*.*s(0x%06x,%d) Submap ALL-FREE {\n",
325e92324a2SMatthew Dillon 			    TABME,
326e92324a2SMatthew Dillon 			    blk,
327b7875890SDavid E. O'Brien 			    radix
328e92324a2SMatthew Dillon 			);
329e92324a2SMatthew Dillon 		}
330ae3a37adSRobert Watson #ifdef DEBUG_SWAPINFO
331e92324a2SMatthew Dillon 		/*
332e92324a2SMatthew Dillon 		 * Note: both dmmax and radix are powers of 2.  However, dmmax
333e92324a2SMatthew Dillon 		 * may be larger then radix so use a smaller increment if
334e92324a2SMatthew Dillon 		 * necessary.
335e92324a2SMatthew Dillon 		 */
336e92324a2SMatthew Dillon 		{
337e92324a2SMatthew Dillon 			int t;
338e92324a2SMatthew Dillon 			int tinc = dmmax;
339e92324a2SMatthew Dillon 
340e92324a2SMatthew Dillon 			while (tinc > radix)
341e92324a2SMatthew Dillon 				tinc >>= 1;
342e92324a2SMatthew Dillon 
343e92324a2SMatthew Dillon 			for (t = blk; t < blk + radix; t += tinc) {
344e92324a2SMatthew Dillon 				int u = (nswdev) ? (t / dmmax % nswdev) : 0;
345e92324a2SMatthew Dillon 
346e92324a2SMatthew Dillon 				if (u < ti)
347e92324a2SMatthew Dillon 					swap_ary[u].ksw_used -= tinc;
348e92324a2SMatthew Dillon 				if (ti >= 0)
349e92324a2SMatthew Dillon 					swap_ary[ti].ksw_used -= tinc;
350e92324a2SMatthew Dillon 			}
351e92324a2SMatthew Dillon 		}
352ae3a37adSRobert Watson #endif
353e92324a2SMatthew Dillon 	} else if (meta.u.bmu_avail == 0) {
354e92324a2SMatthew Dillon 		/*
355e92324a2SMatthew Dillon 		 * Meta node if all used
356e92324a2SMatthew Dillon 		 */
357e92324a2SMatthew Dillon 		if (flags & SWIF_DUMP_TREE) {
358e92324a2SMatthew Dillon 			printf("%*.*s(0x%06x,%d) Submap ALL-ALLOCATED\n",
359e92324a2SMatthew Dillon 			    TABME,
360e92324a2SMatthew Dillon 			    blk,
361b7875890SDavid E. O'Brien 			    radix
362e92324a2SMatthew Dillon 			);
363e92324a2SMatthew Dillon 		}
364e92324a2SMatthew Dillon 	} else {
365e92324a2SMatthew Dillon 		/*
366e92324a2SMatthew Dillon 		 * Meta node if not all free
367e92324a2SMatthew Dillon 		 */
368e92324a2SMatthew Dillon 		int i;
369e92324a2SMatthew Dillon 		int next_skip;
370e92324a2SMatthew Dillon 
371e92324a2SMatthew Dillon 		if (flags & SWIF_DUMP_TREE) {
372e92324a2SMatthew Dillon 			printf("%*.*s(0x%06x,%d) Submap avail=%d big=%d {\n",
373e92324a2SMatthew Dillon 			    TABME,
374e92324a2SMatthew Dillon 			    blk,
375e92324a2SMatthew Dillon 			    radix,
376e92324a2SMatthew Dillon 			    (int)meta.u.bmu_avail,
377e92324a2SMatthew Dillon 			    meta.bm_bighint
378e92324a2SMatthew Dillon 			);
379e92324a2SMatthew Dillon 		}
380e92324a2SMatthew Dillon 
381876c5c11SMatthew Dillon 		radix >>= BLIST_META_RADIX_SHIFT;
382876c5c11SMatthew Dillon 		next_skip = skip >> BLIST_META_RADIX_SHIFT;
383876c5c11SMatthew Dillon 
384e92324a2SMatthew Dillon 		for (i = 1; i <= skip; i += next_skip) {
385e92324a2SMatthew Dillon 			int r;
386e92324a2SMatthew Dillon 			daddr_t vcount = (count > radix) ? radix : count;
387e92324a2SMatthew Dillon 
388e92324a2SMatthew Dillon 			r = scanradix(
389e92324a2SMatthew Dillon 			    &scan[i],
390e92324a2SMatthew Dillon 			    blk,
391e92324a2SMatthew Dillon 			    radix,
392e92324a2SMatthew Dillon 			    next_skip - 1,
393e92324a2SMatthew Dillon 			    vcount,
394e92324a2SMatthew Dillon 			    kd,
395e92324a2SMatthew Dillon 			    dmmax,
396e92324a2SMatthew Dillon 			    nswdev,
397e92324a2SMatthew Dillon 			    swap_ary,
398e92324a2SMatthew Dillon 			    swap_max,
399e92324a2SMatthew Dillon 			    tab + 4,
400e92324a2SMatthew Dillon 			    flags
401e92324a2SMatthew Dillon 			);
402e92324a2SMatthew Dillon 			if (r < 0)
403e92324a2SMatthew Dillon 				break;
404e92324a2SMatthew Dillon 			blk += radix;
405e92324a2SMatthew Dillon 		}
406e92324a2SMatthew Dillon 		if (flags & SWIF_DUMP_TREE) {
407e92324a2SMatthew Dillon 			printf("%*.*s}\n", TABME);
408e92324a2SMatthew Dillon 		}
409e92324a2SMatthew Dillon 	}
410e92324a2SMatthew Dillon 	return(0);
411e92324a2SMatthew Dillon }
412e92324a2SMatthew Dillon 
413e92324a2SMatthew Dillon static void
41445908a6aSBruce Evans getswapinfo_radix(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, int flags)
415e92324a2SMatthew Dillon {
416e92324a2SMatthew Dillon 	struct blist *swapblist = NULL;
417e92324a2SMatthew Dillon 	struct blist blcopy = { 0 };
418e92324a2SMatthew Dillon 
419ae3a37adSRobert Watson 	if (!nlist_init(kd)) {
420ae3a37adSRobert Watson 		fprintf(stderr, "radix tree: nlist_init failed!\n");
421ae3a37adSRobert Watson 		return;
422ae3a37adSRobert Watson 	}
423ae3a37adSRobert Watson 
424e92324a2SMatthew Dillon 	KGET(NL_SWAPBLIST, swapblist);
425f3401d0cSMatthew Dillon 
426f3401d0cSMatthew Dillon 	if (swapblist == NULL) {
427f3401d0cSMatthew Dillon 		if (flags & SWIF_DUMP_TREE)
428f3401d0cSMatthew Dillon 			printf("radix tree: NULL - no swap in system\n");
429f3401d0cSMatthew Dillon 		return;
430f3401d0cSMatthew Dillon 	}
431f3401d0cSMatthew Dillon 
432e92324a2SMatthew Dillon 	KGET2(swapblist, &blcopy, sizeof(blcopy), "*swapblist");
433e92324a2SMatthew Dillon 
434e92324a2SMatthew Dillon 	if (flags & SWIF_DUMP_TREE) {
435e92324a2SMatthew Dillon 		printf("radix tree: %d/%d/%d blocks, %dK wired\n",
436e92324a2SMatthew Dillon 			blcopy.bl_free,
437e92324a2SMatthew Dillon 			blcopy.bl_blocks,
438e92324a2SMatthew Dillon 			blcopy.bl_radix,
439b7875890SDavid E. O'Brien 			(int)((blcopy.bl_rootblks * sizeof(blmeta_t) + 1023)/
440b7875890SDavid E. O'Brien 			    1024)
441e92324a2SMatthew Dillon 		);
442e92324a2SMatthew Dillon 	}
443e92324a2SMatthew Dillon 	scanradix(
444e92324a2SMatthew Dillon 	    blcopy.bl_root,
445e92324a2SMatthew Dillon 	    0,
446e92324a2SMatthew Dillon 	    blcopy.bl_radix,
447e92324a2SMatthew Dillon 	    blcopy.bl_skip,
448e92324a2SMatthew Dillon 	    blcopy.bl_rootblks,
449e92324a2SMatthew Dillon 	    kd,
450e92324a2SMatthew Dillon 	    dmmax,
451e92324a2SMatthew Dillon 	    nswdev,
452e92324a2SMatthew Dillon 	    swap_ary,
453e92324a2SMatthew Dillon 	    swap_max,
454e92324a2SMatthew Dillon 	    0,
455e92324a2SMatthew Dillon 	    flags
456e92324a2SMatthew Dillon 	);
457e92324a2SMatthew Dillon }
458ae3a37adSRobert Watson 
459ae3a37adSRobert Watson #define GETSYSCTL(kd, name, var)                                        \
460ae3a37adSRobert Watson             getsysctl(kd, name, &(var), sizeof(var))
461ae3a37adSRobert Watson #define GETSYSCTL2(kd, pref, suff, buf, var)                            \
462ae3a37adSRobert Watson             getsysctl2(kd, pref, suff, buf, sizeof(buf), &(var),        \
463ae3a37adSRobert Watson 	    sizeof(var))
464ae3a37adSRobert Watson 
465ae3a37adSRobert Watson int
466ae3a37adSRobert Watson kvm_getswapinfo_sysctl(
467ae3a37adSRobert Watson 	kvm_t *kd,
468ae3a37adSRobert Watson 	struct kvm_swap *swap_ary,
469ae3a37adSRobert Watson 	int swap_max,
470ae3a37adSRobert Watson 	int flags
471ae3a37adSRobert Watson ) {
472ae3a37adSRobert Watson 	int ti = 0;
473ae3a37adSRobert Watson 	udev_t dev;
474ae3a37adSRobert Watson 	char node[15];
475ae3a37adSRobert Watson 	char buf[20];
476ae3a37adSRobert Watson 	int used, ttl, i;
477ae3a37adSRobert Watson 
478ae3a37adSRobert Watson 	if (!GETSYSCTL(kd, "vm.nswapdev", unswdev))
479ae3a37adSRobert Watson 		return -1;
480ae3a37adSRobert Watson 
481ae3a37adSRobert Watson 	ti = unswdev;
482ae3a37adSRobert Watson 	if (ti >= swap_max)
483ae3a37adSRobert Watson 		ti = swap_max - 1;
484ae3a37adSRobert Watson 
485ae3a37adSRobert Watson 	if (ti >= 0)
486ae3a37adSRobert Watson 		bzero(swap_ary, sizeof(struct kvm_swap) * (ti + 1));
487ae3a37adSRobert Watson 
488ae3a37adSRobert Watson 	if (!GETSYSCTL(kd, "vm.dmmax", dmmax))
489ae3a37adSRobert Watson 		return -1;
490ae3a37adSRobert Watson 
491ae3a37adSRobert Watson 	for (i = 0; i < unswdev; ++i) {
492ae3a37adSRobert Watson 		if (snprintf(node, sizeof(node), "vm.swapdev%d.", i) >=
493ae3a37adSRobert Watson 		    sizeof(node)) {
494ae3a37adSRobert Watson 			_kvm_err(kd, kd->program, "XXX: node buffer too small");
495ae3a37adSRobert Watson 			return -1;
496ae3a37adSRobert Watson 		}
497ae3a37adSRobert Watson 
498ae3a37adSRobert Watson 		if (!GETSYSCTL2(kd, node, "nblks", buf, ttl))
499ae3a37adSRobert Watson 			return -1;
500ae3a37adSRobert Watson 		if (!GETSYSCTL2(kd, node, "used", buf, used))
501ae3a37adSRobert Watson 			return -1;
502ae3a37adSRobert Watson 		ttl -= dmmax;
503ae3a37adSRobert Watson 
504ae3a37adSRobert Watson 		if (i < ti) {
505ae3a37adSRobert Watson 			if (!GETSYSCTL2(kd, node, "dev", buf, dev))
506ae3a37adSRobert Watson 				return -1;
507ae3a37adSRobert Watson 			if (!GETSYSCTL2(kd, node, "flags", buf,
508ae3a37adSRobert Watson 					swap_ary[i].ksw_flags))
509ae3a37adSRobert Watson 				return -1;
510ae3a37adSRobert Watson 			swap_ary[i].ksw_total = ttl;
511ae3a37adSRobert Watson 			swap_ary[i].ksw_used = used;
512ae3a37adSRobert Watson 			GETSWDEVNAME(dev, swap_ary[i].ksw_devname, flags);
513ae3a37adSRobert Watson 		}
514ae3a37adSRobert Watson 		if (ti >= 0) {
515ae3a37adSRobert Watson 			swap_ary[ti].ksw_total += ttl;
516ae3a37adSRobert Watson 			swap_ary[ti].ksw_used += used;
517ae3a37adSRobert Watson 		}
518ae3a37adSRobert Watson 	}
519ae3a37adSRobert Watson 
520ae3a37adSRobert Watson         return(ti);
521ae3a37adSRobert Watson }
522ae3a37adSRobert Watson 
523ae3a37adSRobert Watson static int
524ae3a37adSRobert Watson nlist_init (
525ae3a37adSRobert Watson 	kvm_t *kd
526ae3a37adSRobert Watson ) {
527ae3a37adSRobert Watson 	struct swdevt *sw;
528ae3a37adSRobert Watson 
529ae3a37adSRobert Watson 	if (kvm_swap_nl_cached)
530ae3a37adSRobert Watson 		return (1);
531ae3a37adSRobert Watson 
532ae3a37adSRobert Watson 	if (kvm_nlist(kd, kvm_swap_nl) < 0)
533ae3a37adSRobert Watson 		return (0);
534ae3a37adSRobert Watson 
535ae3a37adSRobert Watson 	/*
536ae3a37adSRobert Watson 	 * required entries
537ae3a37adSRobert Watson 	 */
538ae3a37adSRobert Watson 	if (
539ae3a37adSRobert Watson 	    kvm_swap_nl[NL_SWDEVT].n_value == 0 ||
540ae3a37adSRobert Watson 	    kvm_swap_nl[NL_NSWDEV].n_value == 0 ||
541ae3a37adSRobert Watson 	    kvm_swap_nl[NL_DMMAX].n_value == 0 ||
542ae3a37adSRobert Watson 	    kvm_swap_nl[NL_SWAPBLIST].n_type == 0
543ae3a37adSRobert Watson 	   ) {
544ae3a37adSRobert Watson 		return (0);
545ae3a37adSRobert Watson 	}
546ae3a37adSRobert Watson 
547ae3a37adSRobert Watson 	/*
548ae3a37adSRobert Watson 	 * get globals, type of swap
549ae3a37adSRobert Watson 	 */
550ae3a37adSRobert Watson 	KGET(NL_NSWDEV, nswdev);
551ae3a37adSRobert Watson 	KGET(NL_DMMAX, dmmax);
552ae3a37adSRobert Watson 
553ae3a37adSRobert Watson 	/*
554ae3a37adSRobert Watson 	 * figure out how many actual swap devices are enabled
555ae3a37adSRobert Watson 	 */
556ae3a37adSRobert Watson 	KGET(NL_SWDEVT, sw);
557ae3a37adSRobert Watson 	for (unswdev = nswdev - 1; unswdev >= 0; --unswdev) {
558ae3a37adSRobert Watson 		struct swdevt swinfo;
559ae3a37adSRobert Watson 
560ae3a37adSRobert Watson 		KGET2(&sw[unswdev], &swinfo, sizeof(swinfo), "swinfo");
561ae3a37adSRobert Watson 		if (swinfo.sw_nblks)
562ae3a37adSRobert Watson 			break;
563ae3a37adSRobert Watson 	}
564ae3a37adSRobert Watson 	++unswdev;
565ae3a37adSRobert Watson 
566ae3a37adSRobert Watson 	kvm_swap_nl_cached = 1;
567ae3a37adSRobert Watson 	return (1);
568ae3a37adSRobert Watson }
569ae3a37adSRobert Watson 
570ae3a37adSRobert Watson static int
571ae3a37adSRobert Watson getsysctl (
572ae3a37adSRobert Watson 	kvm_t *kd,
573ae3a37adSRobert Watson 	char *name,
574ae3a37adSRobert Watson 	void *ptr,
575ae3a37adSRobert Watson 	int len
576ae3a37adSRobert Watson ) {
577ae3a37adSRobert Watson 	int nlen = len;
578ae3a37adSRobert Watson 	if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
579ae3a37adSRobert Watson 		_kvm_err(kd, kd->program, "cannot read sysctl %s", name);
580ae3a37adSRobert Watson 		return (0);
581ae3a37adSRobert Watson 	}
582ae3a37adSRobert Watson 	if (nlen != len) {
583ae3a37adSRobert Watson 		_kvm_err(kd, kd->program, "sysctl %s has unexpected size", name);
584ae3a37adSRobert Watson 		return (0);
585ae3a37adSRobert Watson 	}
586ae3a37adSRobert Watson 	return (1);
587ae3a37adSRobert Watson }
588ae3a37adSRobert Watson 
589ae3a37adSRobert Watson static int
590ae3a37adSRobert Watson getsysctl2 (
591ae3a37adSRobert Watson 	kvm_t *kd,
592ae3a37adSRobert Watson 	char *pref,
593ae3a37adSRobert Watson 	char *suff,
594ae3a37adSRobert Watson 	char *buf,
595ae3a37adSRobert Watson 	int buflen,
596ae3a37adSRobert Watson 	void *ptr,
597ae3a37adSRobert Watson 	int len
598ae3a37adSRobert Watson ) {
599ae3a37adSRobert Watson 	if (strlcpy(buf, pref, buflen) >= buflen) {
600ae3a37adSRobert Watson 		_kvm_err(kd, kd->program, "getsysctl2: string buffer too small");
601ae3a37adSRobert Watson 		return (0);
602ae3a37adSRobert Watson 	}
603ae3a37adSRobert Watson 	if (strlcat(buf, suff, buflen) >= buflen) {
604ae3a37adSRobert Watson 		_kvm_err(kd, kd->program, "getsysctl2: string buffer too small");
605ae3a37adSRobert Watson 		return (0);
606ae3a37adSRobert Watson 	}
607ae3a37adSRobert Watson 	return getsysctl(kd, buf, ptr, len);
608ae3a37adSRobert Watson }
609