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: releng/10.2/lib/libkvm/kvm_getswapinfo.c 217744 2011-01-23 11:08:28Z uqs $"); 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{ 115166550Sjhb int i, ttl; 116166550Sjhb TAILQ_HEAD(, swdevt) swtailq; 117166550Sjhb struct swdevt *sp, swinfo; 118166550Sjhb struct kvm_swap tot; 119166550Sjhb 120166550Sjhb if (!nlist_init(kd)) 121166550Sjhb return (-1); 122166550Sjhb 123166550Sjhb bzero(&tot, sizeof(tot)); 124166550Sjhb KGET(NL_SWTAILQ, &swtailq); 125166550Sjhb sp = TAILQ_FIRST(&swtailq); 126166550Sjhb for (i = 0; sp != NULL; i++) { 127166550Sjhb KGET2(sp, &swinfo, "swinfo"); 128166550Sjhb ttl = swinfo.sw_nblks - dmmax; 129166550Sjhb if (i < swap_max - 1) { 130166550Sjhb bzero(&swap_ary[i], sizeof(swap_ary[i])); 131166550Sjhb swap_ary[i].ksw_total = ttl; 132166550Sjhb swap_ary[i].ksw_used = swinfo.sw_used; 133166550Sjhb swap_ary[i].ksw_flags = swinfo.sw_flags; 134166550Sjhb GETSWDEVNAME(swinfo.sw_dev, swap_ary[i].ksw_devname, 135166550Sjhb flags); 136166550Sjhb } 137166550Sjhb tot.ksw_total += ttl; 138166550Sjhb tot.ksw_used += swinfo.sw_used; 139166550Sjhb sp = TAILQ_NEXT(&swinfo, sw_list); 140166550Sjhb } 141166550Sjhb 142166550Sjhb if (i >= swap_max) 143166550Sjhb i = swap_max - 1; 144166550Sjhb if (i >= 0) 145166550Sjhb swap_ary[i] = tot; 146166550Sjhb 147166550Sjhb return(i); 148166550Sjhb} 149166550Sjhb 15077605Stmm#define GETSYSCTL(kd, name, var) \ 15177605Stmm getsysctl(kd, name, &(var), sizeof(var)) 15272950Srwatson 15377605Stmm/* The maximum MIB length for vm.swap_info and an additional device number */ 15477605Stmm#define SWI_MAXMIB 3 15577605Stmm 15672950Srwatsonint 157217744Suqskvm_getswapinfo_sysctl(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, 158217744Suqs int flags) 159217744Suqs{ 16077605Stmm int ti, ttl; 16177605Stmm size_t mibi, len; 16277605Stmm int soid[SWI_MAXMIB]; 16377605Stmm struct xswdev xsd; 16477605Stmm struct kvm_swap tot; 16572950Srwatson 16677605Stmm if (!GETSYSCTL(kd, "vm.dmmax", dmmax)) 16772950Srwatson return -1; 16872950Srwatson 16977605Stmm mibi = SWI_MAXMIB - 1; 17077605Stmm if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { 17177605Stmm _kvm_err(kd, kd->program, "sysctlnametomib failed: %s", 17277605Stmm strerror(errno)); 17372950Srwatson return -1; 17477605Stmm } 17577605Stmm bzero(&tot, sizeof(tot)); 17677605Stmm for (unswdev = 0;; unswdev++) { 17777605Stmm soid[mibi] = unswdev; 17877605Stmm len = sizeof(xsd); 17977605Stmm if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { 18077605Stmm if (errno == ENOENT) 18177605Stmm break; 18277605Stmm _kvm_err(kd, kd->program, "cannot read sysctl: %s.", 18377605Stmm strerror(errno)); 18472950Srwatson return -1; 18572950Srwatson } 18677605Stmm if (len != sizeof(xsd)) { 18777605Stmm _kvm_err(kd, kd->program, "struct xswdev has unexpected " 18877605Stmm "size; kernel and libkvm out of sync?"); 18972950Srwatson return -1; 19077605Stmm } 19177605Stmm if (xsd.xsw_version != XSWDEV_VERSION) { 19277605Stmm _kvm_err(kd, kd->program, "struct xswdev version " 19377605Stmm "mismatch; kernel and libkvm out of sync?"); 19472950Srwatson return -1; 19577605Stmm } 19672950Srwatson 19777605Stmm ttl = xsd.xsw_nblks - dmmax; 19877605Stmm if (unswdev < swap_max - 1) { 19977605Stmm bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); 20077605Stmm swap_ary[unswdev].ksw_total = ttl; 20177605Stmm swap_ary[unswdev].ksw_used = xsd.xsw_used; 20277605Stmm swap_ary[unswdev].ksw_flags = xsd.xsw_flags; 20377605Stmm GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname, 20477605Stmm flags); 20572950Srwatson } 20677605Stmm tot.ksw_total += ttl; 20777605Stmm tot.ksw_used += xsd.xsw_used; 20872950Srwatson } 20972950Srwatson 21077605Stmm ti = unswdev; 21177605Stmm if (ti >= swap_max) 21277605Stmm ti = swap_max - 1; 21377605Stmm if (ti >= 0) 21477605Stmm swap_ary[ti] = tot; 21577605Stmm 21672950Srwatson return(ti); 21772950Srwatson} 21872950Srwatson 21972950Srwatsonstatic int 220166550Sjhbnlist_init(kvm_t *kd) 221166550Sjhb{ 222166550Sjhb 223166550Sjhb if (kvm_swap_nl_cached) 224166550Sjhb return (1); 225166550Sjhb 226166550Sjhb if (kvm_nlist(kd, kvm_swap_nl) < 0) 227166550Sjhb return (0); 228166550Sjhb 229166550Sjhb /* Required entries */ 230166550Sjhb if (kvm_swap_nl[NL_SWTAILQ].n_value == 0) { 231166550Sjhb _kvm_err(kd, kd->program, "unable to find swtailq"); 232166550Sjhb return (0); 233166550Sjhb } 234166550Sjhb 235166550Sjhb if (kvm_swap_nl[NL_DMMAX].n_value == 0) { 236166550Sjhb _kvm_err(kd, kd->program, "unable to find dmmax"); 237166550Sjhb return (0); 238166550Sjhb } 239166550Sjhb 240166550Sjhb /* Get globals, type of swap */ 241166550Sjhb KGET(NL_DMMAX, &dmmax); 242166550Sjhb 243166550Sjhb kvm_swap_nl_cached = 1; 244166550Sjhb return (1); 245166550Sjhb} 246166550Sjhb 247166550Sjhbstatic int 248217744Suqsgetsysctl(kvm_t *kd, const char *name, void *ptr, size_t len) 249217744Suqs{ 25077605Stmm size_t nlen = len; 25172950Srwatson if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 25277605Stmm _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name, 25377605Stmm strerror(errno)); 25472950Srwatson return (0); 25572950Srwatson } 25672950Srwatson if (nlen != len) { 25772950Srwatson _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name); 25872950Srwatson return (0); 25972950Srwatson } 26072950Srwatson return (1); 26172950Srwatson} 262