143045Sdillon/* 243045Sdillon * Copyright (c) 1999, Matthew Dillon. All Rights Reserved. 3132935Simp * Copyright (c) 2001, Thomas Moestl. All Rights Reserved. 443045Sdillon * 543045Sdillon * Redistribution and use in source and binary forms, with or without 6132935Simp * modification, are permitted provided that the following conditions 7132935Simp * are met: 8132935Simp * 1. Redistributions of source code must retain the above copyright 9132935Simp * notice, this list of conditions and the following disclaimer. 10132935Simp * 2. Redistributions in binary form must reproduce the above copyright 11132935Simp * notice, this list of conditions and the following disclaimer in the 12132935Simp * documentation and/or other materials provided with the distribution. 13291372Sjhb * 14132935Simp * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15132935Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16132935Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17132935Simp * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18132935Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19132935Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20132935Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21132935Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22132935Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23132935Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24132935Simp * SUCH DAMAGE. 2543045Sdillon */ 2643045Sdillon 2783551Sdillon#include <sys/cdefs.h> 2883551Sdillon__FBSDID("$FreeBSD: releng/11.0/lib/libkvm/kvm_getswapinfo.c 291406 2015-11-27 18:58:26Z jhb $"); 2943045Sdillon 3043045Sdillon#include <sys/param.h> 3143045Sdillon#include <sys/time.h> 3243045Sdillon#include <sys/stat.h> 3343045Sdillon#include <sys/blist.h> 3472950Srwatson#include <sys/sysctl.h> 3543045Sdillon 36166550Sjhb#include <vm/swap_pager.h> 3777605Stmm#include <vm/vm_param.h> 3877605Stmm 3943045Sdillon#include <err.h> 4077605Stmm#include <errno.h> 4143045Sdillon#include <fcntl.h> 4243045Sdillon#include <kvm.h> 4343045Sdillon#include <nlist.h> 4469793Sobrien#include <paths.h> 4543045Sdillon#include <stdio.h> 4643045Sdillon#include <stdlib.h> 4743045Sdillon#include <string.h> 4843045Sdillon#include <unistd.h> 4972950Srwatson#include <limits.h> 5043045Sdillon 5172950Srwatson#include "kvm_private.h" 5272950Srwatson 53166550Sjhbstatic struct nlist kvm_swap_nl[] = { 54217744Suqs { .n_name = "_swtailq" }, /* list of swap devices and sizes */ 55217744Suqs { .n_name = "_dmmax" }, /* maximum size of a swap block */ 56217744Suqs { .n_name = NULL } 57166550Sjhb}; 5843045Sdillon 59166550Sjhb#define NL_SWTAILQ 0 60166550Sjhb#define NL_DMMAX 1 61166550Sjhb 6243045Sdillonstatic int kvm_swap_nl_cached = 0; 6372950Srwatsonstatic int unswdev; /* number of found swap dev's */ 6443045Sdillonstatic int dmmax; 6543045Sdillon 66166550Sjhbstatic int kvm_getswapinfo_kvm(kvm_t *, struct kvm_swap *, int, int); 6772950Srwatsonstatic int kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int); 68166550Sjhbstatic int nlist_init(kvm_t *); 69217744Suqsstatic int getsysctl(kvm_t *, const char *, void *, size_t); 7043045Sdillon 71166550Sjhb#define KREAD(kd, addr, obj) \ 72166550Sjhb (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) 73166550Sjhb#define KGET(idx, var) \ 74166550Sjhb KGET2(kvm_swap_nl[(idx)].n_value, var, kvm_swap_nl[(idx)].n_name) 75166550Sjhb#define KGET2(addr, var, msg) \ 76166550Sjhb if (KREAD(kd, (u_long)(addr), (var))) { \ 77166550Sjhb _kvm_err(kd, kd->program, "cannot read %s", msg); \ 78166550Sjhb return (-1); \ 79166550Sjhb } 80291372Sjhb 8177605Stmm#define GETSWDEVNAME(dev, str, flags) \ 8277605Stmm if (dev == NODEV) { \ 8377605Stmm strlcpy(str, "[NFS swap]", sizeof(str)); \ 8477605Stmm } else { \ 8577605Stmm snprintf( \ 8677605Stmm str, sizeof(str),"%s%s", \ 8777605Stmm ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \ 8877605Stmm devname(dev, S_IFCHR) \ 8977605Stmm ); \ 9072950Srwatson } 9172950Srwatson 9243045Sdillonint 93217744Suqskvm_getswapinfo(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, int flags) 94217744Suqs{ 9543045Sdillon 9643045Sdillon /* 9743045Sdillon * clear cache 9843045Sdillon */ 9943045Sdillon if (kd == NULL) { 10043045Sdillon kvm_swap_nl_cached = 0; 10143045Sdillon return(0); 10243045Sdillon } 10343045Sdillon 10472950Srwatson if (ISALIVE(kd)) { 10572950Srwatson return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags); 10672950Srwatson } else { 107166550Sjhb return kvm_getswapinfo_kvm(kd, swap_ary, swap_max, flags); 10872950Srwatson } 10972950Srwatson} 11043045Sdillon 111166550Sjhbint 112217744Suqskvm_getswapinfo_kvm(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, 113217744Suqs int flags) 114217744Suqs{ 115166550Sjhb int i, ttl; 116166550Sjhb TAILQ_HEAD(, swdevt) swtailq; 117166550Sjhb struct swdevt *sp, swinfo; 118166550Sjhb struct kvm_swap tot; 119166550Sjhb 120291406Sjhb if (!kd->arch->ka_native(kd)) { 121291406Sjhb _kvm_err(kd, kd->program, 122291406Sjhb "cannot read swapinfo from non-native core"); 123291406Sjhb return (-1); 124291406Sjhb } 125291406Sjhb 126166550Sjhb if (!nlist_init(kd)) 127166550Sjhb return (-1); 128166550Sjhb 129166550Sjhb bzero(&tot, sizeof(tot)); 130166550Sjhb KGET(NL_SWTAILQ, &swtailq); 131166550Sjhb sp = TAILQ_FIRST(&swtailq); 132166550Sjhb for (i = 0; sp != NULL; i++) { 133166550Sjhb KGET2(sp, &swinfo, "swinfo"); 134166550Sjhb ttl = swinfo.sw_nblks - dmmax; 135166550Sjhb if (i < swap_max - 1) { 136166550Sjhb bzero(&swap_ary[i], sizeof(swap_ary[i])); 137166550Sjhb swap_ary[i].ksw_total = ttl; 138166550Sjhb swap_ary[i].ksw_used = swinfo.sw_used; 139166550Sjhb swap_ary[i].ksw_flags = swinfo.sw_flags; 140166550Sjhb GETSWDEVNAME(swinfo.sw_dev, swap_ary[i].ksw_devname, 141166550Sjhb flags); 142166550Sjhb } 143166550Sjhb tot.ksw_total += ttl; 144166550Sjhb tot.ksw_used += swinfo.sw_used; 145166550Sjhb sp = TAILQ_NEXT(&swinfo, sw_list); 146166550Sjhb } 147166550Sjhb 148166550Sjhb if (i >= swap_max) 149166550Sjhb i = swap_max - 1; 150166550Sjhb if (i >= 0) 151166550Sjhb swap_ary[i] = tot; 152166550Sjhb 153166550Sjhb return(i); 154166550Sjhb} 155166550Sjhb 15677605Stmm#define GETSYSCTL(kd, name, var) \ 15777605Stmm getsysctl(kd, name, &(var), sizeof(var)) 15872950Srwatson 15977605Stmm/* The maximum MIB length for vm.swap_info and an additional device number */ 16077605Stmm#define SWI_MAXMIB 3 16177605Stmm 16272950Srwatsonint 163217744Suqskvm_getswapinfo_sysctl(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, 164217744Suqs int flags) 165217744Suqs{ 16677605Stmm int ti, ttl; 16777605Stmm size_t mibi, len; 16877605Stmm int soid[SWI_MAXMIB]; 16977605Stmm struct xswdev xsd; 17077605Stmm struct kvm_swap tot; 17172950Srwatson 17277605Stmm if (!GETSYSCTL(kd, "vm.dmmax", dmmax)) 17372950Srwatson return -1; 17472950Srwatson 17577605Stmm mibi = SWI_MAXMIB - 1; 17677605Stmm if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { 17777605Stmm _kvm_err(kd, kd->program, "sysctlnametomib failed: %s", 17877605Stmm strerror(errno)); 17972950Srwatson return -1; 18077605Stmm } 18177605Stmm bzero(&tot, sizeof(tot)); 18277605Stmm for (unswdev = 0;; unswdev++) { 18377605Stmm soid[mibi] = unswdev; 18477605Stmm len = sizeof(xsd); 18577605Stmm if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { 18677605Stmm if (errno == ENOENT) 18777605Stmm break; 18877605Stmm _kvm_err(kd, kd->program, "cannot read sysctl: %s.", 18977605Stmm strerror(errno)); 19072950Srwatson return -1; 19172950Srwatson } 19277605Stmm if (len != sizeof(xsd)) { 19377605Stmm _kvm_err(kd, kd->program, "struct xswdev has unexpected " 19477605Stmm "size; kernel and libkvm out of sync?"); 19572950Srwatson return -1; 19677605Stmm } 19777605Stmm if (xsd.xsw_version != XSWDEV_VERSION) { 19877605Stmm _kvm_err(kd, kd->program, "struct xswdev version " 19977605Stmm "mismatch; kernel and libkvm out of sync?"); 20072950Srwatson return -1; 20177605Stmm } 20272950Srwatson 20377605Stmm ttl = xsd.xsw_nblks - dmmax; 20477605Stmm if (unswdev < swap_max - 1) { 20577605Stmm bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); 20677605Stmm swap_ary[unswdev].ksw_total = ttl; 20777605Stmm swap_ary[unswdev].ksw_used = xsd.xsw_used; 20877605Stmm swap_ary[unswdev].ksw_flags = xsd.xsw_flags; 20977605Stmm GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname, 21077605Stmm flags); 21172950Srwatson } 21277605Stmm tot.ksw_total += ttl; 21377605Stmm tot.ksw_used += xsd.xsw_used; 21472950Srwatson } 21572950Srwatson 21677605Stmm ti = unswdev; 21777605Stmm if (ti >= swap_max) 21877605Stmm ti = swap_max - 1; 21977605Stmm if (ti >= 0) 22077605Stmm swap_ary[ti] = tot; 22177605Stmm 22272950Srwatson return(ti); 22372950Srwatson} 22472950Srwatson 22572950Srwatsonstatic int 226166550Sjhbnlist_init(kvm_t *kd) 227166550Sjhb{ 228166550Sjhb 229166550Sjhb if (kvm_swap_nl_cached) 230166550Sjhb return (1); 231166550Sjhb 232166550Sjhb if (kvm_nlist(kd, kvm_swap_nl) < 0) 233166550Sjhb return (0); 234166550Sjhb 235166550Sjhb /* Required entries */ 236166550Sjhb if (kvm_swap_nl[NL_SWTAILQ].n_value == 0) { 237166550Sjhb _kvm_err(kd, kd->program, "unable to find swtailq"); 238166550Sjhb return (0); 239166550Sjhb } 240291372Sjhb 241166550Sjhb if (kvm_swap_nl[NL_DMMAX].n_value == 0) { 242166550Sjhb _kvm_err(kd, kd->program, "unable to find dmmax"); 243166550Sjhb return (0); 244166550Sjhb } 245166550Sjhb 246166550Sjhb /* Get globals, type of swap */ 247166550Sjhb KGET(NL_DMMAX, &dmmax); 248166550Sjhb 249166550Sjhb kvm_swap_nl_cached = 1; 250166550Sjhb return (1); 251166550Sjhb} 252166550Sjhb 253166550Sjhbstatic int 254217744Suqsgetsysctl(kvm_t *kd, const char *name, void *ptr, size_t len) 255217744Suqs{ 25677605Stmm size_t nlen = len; 25772950Srwatson if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 25877605Stmm _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name, 25977605Stmm strerror(errno)); 26072950Srwatson return (0); 26172950Srwatson } 26272950Srwatson if (nlen != len) { 26372950Srwatson _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name); 26472950Srwatson return (0); 26572950Srwatson } 26672950Srwatson return (1); 26772950Srwatson} 268