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