2 * Copyright (c) 1999 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $FreeBSD: src/lib/libkvm/kvm_getswapinfo.c,v 1.10.2.4 2003/01/12 09:23:13 dillon Exp $
37 #define _KERNEL_STRUCTURES
39 #include <sys/param.h>
41 #include <sys/ucred.h>
44 #include <sys/blist.h>
45 #include <sys/sysctl.h>
46 #include <vm/vm_param.h>
59 #include "kvm_private.h"
61 static struct nlist kvm_swap_nl[] = {
62 { "_swapblist" }, /* new radix swap list */
63 { "_swdevt" }, /* list of swap devices and sizes */
64 { "_nswdev" }, /* number of swap devices */
65 { "_dmmax" }, /* maximum size of a swap block */
69 #define NL_SWAPBLIST 0
74 static int kvm_swap_nl_cached = 0;
79 static int nlist_init(kvm_t *kd);
80 static void dump_blist(kvm_t *kd);
81 static int kvm_getswapinfo_sysctl(kvm_t *kd, struct kvm_swap *swap_ary,
82 int swap_max, int flags);
84 #define SVAR(var) __STRING(var) /* to force expansion */
85 #define KGET(idx, var) \
86 KGET1(idx, &var, sizeof(var), SVAR(var))
87 #define KGET1(idx, p, s, msg) \
88 KGET2(kvm_swap_nl[idx].n_value, p, s, msg)
89 #define KGET2(addr, p, s, msg) \
90 if (kvm_read(kd, (u_long)(addr), p, s) != s) \
91 warnx("cannot read %s: %s", msg, kvm_geterr(kd))
92 #define KGETN(idx, var) \
93 KGET1N(idx, &var, sizeof(var), SVAR(var))
94 #define KGET1N(idx, p, s, msg) \
95 KGET2N(kvm_swap_nl[idx].n_value, p, s, msg)
96 #define KGET2N(addr, p, s, msg) \
97 ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0)
98 #define KGETRET(addr, p, s, msg) \
99 if (kvm_read(kd, (u_long)(addr), p, s) != s) { \
100 warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \
104 #define GETSWDEVNAME(dev, str, flags) \
105 if (dev == NODEV) { \
106 strlcpy(str, "[NFS swap]", sizeof(str)); \
109 str, sizeof(str), "%s%s", \
110 ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \
111 devname(dev, S_IFCHR) \
118 struct kvm_swap *swap_ary,
125 struct swdevt swinfo;
131 kvm_swap_nl_cached = 0;
139 * Use sysctl if possible
141 if (kvm_ishost(kd) && (flags & SWIF_DUMP_TREE) == 0) {
142 ti = kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags);
157 bzero(swap_ary, sizeof(struct kvm_swap) * (swi + 1));
160 for (i = ti = 0; i < nswdev; ++i) {
161 KGET2(&sw[i], &swinfo, sizeof(swinfo), "swinfo");
163 if (swinfo.sw_nblks == 0)
167 * The first dmmax is never allocated to avoid
168 * trashing the disklabels.
170 ttl = swinfo.sw_nblks - dmmax;
174 swap_ary[swi].ksw_total += ttl;
175 swap_ary[swi].ksw_used += swinfo.sw_nused;
178 swap_ary[ti].ksw_total = ttl;
179 swap_ary[ti].ksw_used = swinfo.sw_nused;
180 swap_ary[ti].ksw_flags = swinfo.sw_flags;
181 GETSWDEVNAME(swinfo.sw_dev, swap_ary[ti].ksw_devname,
187 if (flags & SWIF_DUMP_TREE)
193 nlist_init(kvm_t *kd)
197 struct swdevt swinfo;
199 if (kvm_swap_nl_cached)
202 if (kvm_nlist(kd, kvm_swap_nl) < 0)
208 if (kvm_swap_nl[NL_SWDEVT].n_value == 0 ||
209 kvm_swap_nl[NL_NSWDEV].n_value == 0 ||
210 kvm_swap_nl[NL_DMMAX].n_value == 0 ||
211 kvm_swap_nl[NL_SWAPBLIST].n_type == 0) {
216 * get globals, type of swap
218 KGET(NL_NSWDEV, nswdev);
219 KGET(NL_DMMAX, dmmax);
222 * figure out how many actual swap devices are enabled
225 for (i = unswdev = 0; i < nswdev; ++i) {
226 KGET2(&sw[i], &swinfo, sizeof(swinfo), "swinfo");
232 kvm_swap_nl_cached = 1;
237 * scanradix() - support routine for radix scanner
240 #define TABME tab, tab, ""
245 blmeta_t *scan_cache,
257 blmeta_t scan_array[BLIST_BMAP_RADIX];
258 int64_t avail_tmp = 0;
264 } else if (skip == BLIST_META_RADIX) {
265 if (kvm_read(kd, (u_long)scan, scan_array, sizeof(scan_array)) != sizeof(scan_array)) {
266 warnx("cannot read %s: %s", "blmeta_t", kvm_geterr(kd));
267 bzero(scan_array, sizeof(scan_array));
269 meta = scan_array[0];
271 KGET2(scan, &meta, sizeof(meta), "blmeta_t");
277 if (meta.bm_bighint == (swblk_t)-1) {
278 printf("%*.*s(0x%06jx,%jd) Terminator\n",
286 if (radix == BLIST_BMAP_RADIX) {
290 printf("%*.*s(0x%06jx,%jd) Bitmap %016jx big=%jd\n",
294 (intmax_t)meta.u.bmu_bitmap,
295 (intmax_t)meta.bm_bighint
298 if (meta.u.bmu_bitmap) {
299 for (i = 0; i < BLIST_BMAP_RADIX; ++i) {
300 if (meta.u.bmu_bitmap & (1 << i))
304 } else if (meta.u.bmu_avail == radix) {
306 * Meta node if all free
308 printf("%*.*s(0x%06jx,%jd) Submap ALL-FREE (big=%jd) {\n",
312 (intmax_t)meta.bm_bighint
315 } else if (meta.u.bmu_avail == 0) {
317 * Meta node if all used
319 printf("%*.*s(0x%06jx,%jd) Submap ALL-ALLOCATED (big=%jd)\n",
323 (intmax_t)meta.bm_bighint
327 * Meta node if not all free
329 printf("%*.*s(0x%06jx,%jd) Submap avail=%jd big=%jd {\n",
333 (intmax_t)meta.u.bmu_avail,
334 (intmax_t)meta.bm_bighint
337 radix /= BLIST_META_RADIX;
338 next_skip = skip / BLIST_META_RADIX;
340 for (im = 1; im <= skip; im += next_skip) {
342 swblk_t vcount = (count > radix) ?
343 (swblk_t)radix : count;
347 ((next_skip == 1) ? &scan_array[im] : NULL),
360 blk += (swblk_t)radix;
362 *availp += avail_tmp;
363 if (avail_tmp == meta.u.bmu_avail)
364 printf("%*.*s}\n", TABME);
366 printf("%*.*s} (AVAIL MISMATCH %jd/%jd\n",
369 (intmax_t)meta.u.bmu_avail);
375 dump_blist(kvm_t *kd)
377 struct blist *swapblist = NULL;
378 struct blist blcopy = { 0 };
381 KGET(NL_SWAPBLIST, swapblist);
383 if (swapblist == NULL) {
384 printf("radix tree: NULL - no swap in system\n");
388 KGET2(swapblist, &blcopy, sizeof(blcopy), "*swapblist");
390 printf("radix tree: %jd/%jd/%jd blocks, %jdK wired\n",
391 (intmax_t)blcopy.bl_free,
392 (intmax_t)blcopy.bl_blocks,
393 (intmax_t)blcopy.bl_radix,
394 (intmax_t)((blcopy.bl_rootblks * sizeof(blmeta_t) + 1023)/
411 printf("final availability: %jd\n", (intmax_t)avail);
416 kvm_getswapinfo_sysctl(kvm_t *kd, struct kvm_swap *swap_ary,
417 int swap_max, int flags)
428 if (sysctlbyname("vm.swap_info_array", NULL, &bytes, NULL, 0) < 0)
433 xswbuf = malloc(bytes);
434 if (sysctlbyname("vm.swap_info_array", xswbuf, &bytes, NULL, 0) < 0) {
444 * Calculate size of xsw entry returned by kernel (it can be larger
445 * than the one we have if there is a version mismatch).
447 ksize = ((struct xswdev *)xswbuf)->xsw_size;
448 n = (int)(bytes / ksize);
451 * Calculate the number of live swap devices and calculate
452 * the swap_ary[] index used for the cumulative result (swi)
454 for (i = swi = 0; i < n; ++i) {
455 xsw = (void *)((char *)xswbuf + i * ksize);
456 if ((xsw->xsw_flags & SW_FREED) == 0)
463 bzero(swap_ary, sizeof(struct kvm_swap) * (swi + 1));
466 * Accumulate results. If the provided swap_ary[] is too
467 * small will only populate up to the available entries,
468 * but we always populate the cumulative results entry.
470 for (i = ti = 0; i < n; ++i) {
471 xsw = (void *)((char *)xswbuf + i * ksize);
473 if ((xsw->xsw_flags & SW_FREED) == 0)
476 swap_ary[swi].ksw_total += xsw->xsw_nblks;
477 swap_ary[swi].ksw_used += xsw->xsw_used;
480 swap_ary[ti].ksw_total = xsw->xsw_nblks;
481 swap_ary[ti].ksw_used = xsw->xsw_used;
482 swap_ary[ti].ksw_flags = xsw->xsw_flags;
483 GETSWDEVNAME(xsw->xsw_dev, swap_ary[ti].ksw_devname,