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. 13132935Simp * 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: stable/10/lib/libkvm/kvm_getswapinfo.c 312253 2017-01-16 03:52:20Z pfg $"); 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 } 80166550Sjhb 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{ 115312253Spfg int i; 116312253Spfg swblk_t ttl; 117166550Sjhb TAILQ_HEAD(, swdevt) swtailq; 118166550Sjhb struct swdevt *sp, swinfo; 119166550Sjhb struct kvm_swap tot; 120166550Sjhb 121166550Sjhb if (!nlist_init(kd)) 122166550Sjhb return (-1); 123166550Sjhb 124166550Sjhb bzero(&tot, sizeof(tot)); 125166550Sjhb KGET(NL_SWTAILQ, &swtailq); 126166550Sjhb sp = TAILQ_FIRST(&swtailq); 127166550Sjhb for (i = 0; sp != NULL; i++) { 128166550Sjhb KGET2(sp, &swinfo, "swinfo"); 129166550Sjhb ttl = swinfo.sw_nblks - dmmax; 130166550Sjhb if (i < swap_max - 1) { 131166550Sjhb bzero(&swap_ary[i], sizeof(swap_ary[i])); 132166550Sjhb swap_ary[i].ksw_total = ttl; 133166550Sjhb swap_ary[i].ksw_used = swinfo.sw_used; 134166550Sjhb swap_ary[i].ksw_flags = swinfo.sw_flags; 135166550Sjhb GETSWDEVNAME(swinfo.sw_dev, swap_ary[i].ksw_devname, 136166550Sjhb flags); 137166550Sjhb } 138166550Sjhb tot.ksw_total += ttl; 139166550Sjhb tot.ksw_used += swinfo.sw_used; 140166550Sjhb sp = TAILQ_NEXT(&swinfo, sw_list); 141166550Sjhb } 142166550Sjhb 143166550Sjhb if (i >= swap_max) 144166550Sjhb i = swap_max - 1; 145166550Sjhb if (i >= 0) 146166550Sjhb swap_ary[i] = tot; 147166550Sjhb 148166550Sjhb return(i); 149166550Sjhb} 150166550Sjhb 15177605Stmm#define GETSYSCTL(kd, name, var) \ 15277605Stmm getsysctl(kd, name, &(var), sizeof(var)) 15372950Srwatson 15477605Stmm/* The maximum MIB length for vm.swap_info and an additional device number */ 15577605Stmm#define SWI_MAXMIB 3 15677605Stmm 15772950Srwatsonint 158217744Suqskvm_getswapinfo_sysctl(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, 159217744Suqs int flags) 160217744Suqs{ 161312253Spfg int ti; 162312253Spfg swblk_t ttl; 16377605Stmm size_t mibi, len; 16477605Stmm int soid[SWI_MAXMIB]; 16577605Stmm struct xswdev xsd; 16677605Stmm struct kvm_swap tot; 16772950Srwatson 16877605Stmm if (!GETSYSCTL(kd, "vm.dmmax", dmmax)) 16972950Srwatson return -1; 17072950Srwatson 17177605Stmm mibi = SWI_MAXMIB - 1; 17277605Stmm if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { 17377605Stmm _kvm_err(kd, kd->program, "sysctlnametomib failed: %s", 17477605Stmm strerror(errno)); 17572950Srwatson return -1; 17677605Stmm } 17777605Stmm bzero(&tot, sizeof(tot)); 17877605Stmm for (unswdev = 0;; unswdev++) { 17977605Stmm soid[mibi] = unswdev; 18077605Stmm len = sizeof(xsd); 18177605Stmm if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { 18277605Stmm if (errno == ENOENT) 18377605Stmm break; 18477605Stmm _kvm_err(kd, kd->program, "cannot read sysctl: %s.", 18577605Stmm strerror(errno)); 18672950Srwatson return -1; 18772950Srwatson } 18877605Stmm if (len != sizeof(xsd)) { 18977605Stmm _kvm_err(kd, kd->program, "struct xswdev has unexpected " 19077605Stmm "size; kernel and libkvm out of sync?"); 19172950Srwatson return -1; 19277605Stmm } 19377605Stmm if (xsd.xsw_version != XSWDEV_VERSION) { 19477605Stmm _kvm_err(kd, kd->program, "struct xswdev version " 19577605Stmm "mismatch; kernel and libkvm out of sync?"); 19672950Srwatson return -1; 19777605Stmm } 19872950Srwatson 19977605Stmm ttl = xsd.xsw_nblks - dmmax; 20077605Stmm if (unswdev < swap_max - 1) { 20177605Stmm bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); 20277605Stmm swap_ary[unswdev].ksw_total = ttl; 20377605Stmm swap_ary[unswdev].ksw_used = xsd.xsw_used; 20477605Stmm swap_ary[unswdev].ksw_flags = xsd.xsw_flags; 20577605Stmm GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname, 20677605Stmm flags); 20772950Srwatson } 20877605Stmm tot.ksw_total += ttl; 20977605Stmm tot.ksw_used += xsd.xsw_used; 21072950Srwatson } 21172950Srwatson 21277605Stmm ti = unswdev; 21377605Stmm if (ti >= swap_max) 21477605Stmm ti = swap_max - 1; 21577605Stmm if (ti >= 0) 21677605Stmm swap_ary[ti] = tot; 21777605Stmm 21872950Srwatson return(ti); 21972950Srwatson} 22072950Srwatson 22172950Srwatsonstatic int 222166550Sjhbnlist_init(kvm_t *kd) 223166550Sjhb{ 224166550Sjhb 225166550Sjhb if (kvm_swap_nl_cached) 226166550Sjhb return (1); 227166550Sjhb 228166550Sjhb if (kvm_nlist(kd, kvm_swap_nl) < 0) 229166550Sjhb return (0); 230166550Sjhb 231166550Sjhb /* Required entries */ 232166550Sjhb if (kvm_swap_nl[NL_SWTAILQ].n_value == 0) { 233166550Sjhb _kvm_err(kd, kd->program, "unable to find swtailq"); 234166550Sjhb return (0); 235166550Sjhb } 236166550Sjhb 237166550Sjhb if (kvm_swap_nl[NL_DMMAX].n_value == 0) { 238166550Sjhb _kvm_err(kd, kd->program, "unable to find dmmax"); 239166550Sjhb return (0); 240166550Sjhb } 241166550Sjhb 242166550Sjhb /* Get globals, type of swap */ 243166550Sjhb KGET(NL_DMMAX, &dmmax); 244166550Sjhb 245166550Sjhb kvm_swap_nl_cached = 1; 246166550Sjhb return (1); 247166550Sjhb} 248166550Sjhb 249166550Sjhbstatic int 250217744Suqsgetsysctl(kvm_t *kd, const char *name, void *ptr, size_t len) 251217744Suqs{ 25277605Stmm size_t nlen = len; 25372950Srwatson if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 25477605Stmm _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name, 25577605Stmm strerror(errno)); 25672950Srwatson return (0); 25772950Srwatson } 25872950Srwatson if (nlen != len) { 25972950Srwatson _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name); 26072950Srwatson return (0); 26172950Srwatson } 26272950Srwatson return (1); 26372950Srwatson} 264