1e92324a2SMatthew Dillon /* 2e92324a2SMatthew Dillon * Copyright (c) 1999, Matthew Dillon. All Rights Reserved. 39e749cc9SWarner Losh * Copyright (c) 2001, Thomas Moestl. All Rights Reserved. 4e92324a2SMatthew Dillon * 5e92324a2SMatthew Dillon * Redistribution and use in source and binary forms, with or without 69e749cc9SWarner Losh * modification, are permitted provided that the following conditions 79e749cc9SWarner Losh * are met: 89e749cc9SWarner Losh * 1. Redistributions of source code must retain the above copyright 99e749cc9SWarner Losh * notice, this list of conditions and the following disclaimer. 109e749cc9SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 119e749cc9SWarner Losh * notice, this list of conditions and the following disclaimer in the 129e749cc9SWarner Losh * documentation and/or other materials provided with the distribution. 139e749cc9SWarner Losh * 149e749cc9SWarner Losh * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 159e749cc9SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 169e749cc9SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 179e749cc9SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 189e749cc9SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 199e749cc9SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 209e749cc9SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 219e749cc9SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 229e749cc9SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 239e749cc9SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 249e749cc9SWarner Losh * SUCH DAMAGE. 25e92324a2SMatthew Dillon */ 26e92324a2SMatthew Dillon 27e67f5b9fSMatthew Dillon #include <sys/cdefs.h> 28e67f5b9fSMatthew Dillon __FBSDID("$FreeBSD$"); 29e92324a2SMatthew Dillon 30e92324a2SMatthew Dillon #include <sys/param.h> 31e92324a2SMatthew Dillon #include <sys/time.h> 32e92324a2SMatthew Dillon #include <sys/stat.h> 33e92324a2SMatthew Dillon #include <sys/blist.h> 34ae3a37adSRobert Watson #include <sys/sysctl.h> 35e92324a2SMatthew Dillon 36e8865cafSJohn Baldwin #include <vm/swap_pager.h> 37e04a7c4aSThomas Moestl #include <vm/vm_param.h> 38e04a7c4aSThomas Moestl 39e92324a2SMatthew Dillon #include <err.h> 40e04a7c4aSThomas Moestl #include <errno.h> 41e92324a2SMatthew Dillon #include <fcntl.h> 42e92324a2SMatthew Dillon #include <kvm.h> 43e92324a2SMatthew Dillon #include <nlist.h> 441a37aa56SDavid E. O'Brien #include <paths.h> 45e92324a2SMatthew Dillon #include <stdio.h> 46e92324a2SMatthew Dillon #include <stdlib.h> 47e92324a2SMatthew Dillon #include <string.h> 48e92324a2SMatthew Dillon #include <unistd.h> 49ae3a37adSRobert Watson #include <limits.h> 50ae3a37adSRobert Watson 51ae3a37adSRobert Watson #include "kvm_private.h" 52e92324a2SMatthew Dillon 53e8865cafSJohn Baldwin static struct nlist kvm_swap_nl[] = { 54e8865cafSJohn Baldwin { "_swtailq" }, /* list of swap devices and sizes */ 55e8865cafSJohn Baldwin { "_dmmax" }, /* maximum size of a swap block */ 56e8865cafSJohn Baldwin { NULL } 57e8865cafSJohn Baldwin }; 58e8865cafSJohn Baldwin 59e8865cafSJohn Baldwin #define NL_SWTAILQ 0 60e8865cafSJohn Baldwin #define NL_DMMAX 1 61e92324a2SMatthew Dillon 62e92324a2SMatthew Dillon static int kvm_swap_nl_cached = 0; 63ae3a37adSRobert Watson static int unswdev; /* number of found swap dev's */ 64e92324a2SMatthew Dillon static int dmmax; 65e92324a2SMatthew Dillon 66e8865cafSJohn Baldwin static int kvm_getswapinfo_kvm(kvm_t *, struct kvm_swap *, int, int); 67ae3a37adSRobert Watson static int kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int); 68e8865cafSJohn Baldwin static int nlist_init(kvm_t *); 69e04a7c4aSThomas Moestl static int getsysctl(kvm_t *, char *, void *, size_t); 70e92324a2SMatthew Dillon 71e8865cafSJohn Baldwin #define KREAD(kd, addr, obj) \ 72e8865cafSJohn Baldwin (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) 73e8865cafSJohn Baldwin #define KGET(idx, var) \ 74e8865cafSJohn Baldwin KGET2(kvm_swap_nl[(idx)].n_value, var, kvm_swap_nl[(idx)].n_name) 75e8865cafSJohn Baldwin #define KGET2(addr, var, msg) \ 76e8865cafSJohn Baldwin if (KREAD(kd, (u_long)(addr), (var))) { \ 77e8865cafSJohn Baldwin _kvm_err(kd, kd->program, "cannot read %s", msg); \ 78e8865cafSJohn Baldwin return (-1); \ 79e8865cafSJohn Baldwin } 80e8865cafSJohn Baldwin 81ae3a37adSRobert Watson #define GETSWDEVNAME(dev, str, flags) \ 82ae3a37adSRobert Watson if (dev == NODEV) { \ 83ae3a37adSRobert Watson strlcpy(str, "[NFS swap]", sizeof(str)); \ 84ae3a37adSRobert Watson } else { \ 85ae3a37adSRobert Watson snprintf( \ 86ae3a37adSRobert Watson str, sizeof(str),"%s%s", \ 87ae3a37adSRobert Watson ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \ 88ae3a37adSRobert Watson devname(dev, S_IFCHR) \ 89ae3a37adSRobert Watson ); \ 90ae3a37adSRobert Watson } 91ae3a37adSRobert Watson 92e92324a2SMatthew Dillon int 93e92324a2SMatthew Dillon kvm_getswapinfo( 94e92324a2SMatthew Dillon kvm_t *kd, 95e92324a2SMatthew Dillon struct kvm_swap *swap_ary, 96e92324a2SMatthew Dillon int swap_max, 97e92324a2SMatthew Dillon int flags 98e92324a2SMatthew Dillon ) { 99e92324a2SMatthew Dillon 100e92324a2SMatthew Dillon /* 101e92324a2SMatthew Dillon * clear cache 102e92324a2SMatthew Dillon */ 103e92324a2SMatthew Dillon if (kd == NULL) { 104e92324a2SMatthew Dillon kvm_swap_nl_cached = 0; 105e92324a2SMatthew Dillon return(0); 106e92324a2SMatthew Dillon } 107e92324a2SMatthew Dillon 108ae3a37adSRobert Watson if (ISALIVE(kd)) { 109ae3a37adSRobert Watson return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags); 110ae3a37adSRobert Watson } else { 111e8865cafSJohn Baldwin return kvm_getswapinfo_kvm(kd, swap_ary, swap_max, flags); 112ae3a37adSRobert Watson } 113ae3a37adSRobert Watson } 114ae3a37adSRobert Watson 115e8865cafSJohn Baldwin int 116e8865cafSJohn Baldwin kvm_getswapinfo_kvm( 117e8865cafSJohn Baldwin kvm_t *kd, 118e8865cafSJohn Baldwin struct kvm_swap *swap_ary, 119e8865cafSJohn Baldwin int swap_max, 120e8865cafSJohn Baldwin int flags 121e8865cafSJohn Baldwin ) { 122e8865cafSJohn Baldwin int i, ttl; 123e8865cafSJohn Baldwin TAILQ_HEAD(, swdevt) swtailq; 124e8865cafSJohn Baldwin struct swdevt *sp, swinfo; 125e8865cafSJohn Baldwin struct kvm_swap tot; 126e8865cafSJohn Baldwin 127e8865cafSJohn Baldwin if (!nlist_init(kd)) 128e8865cafSJohn Baldwin return (-1); 129e8865cafSJohn Baldwin 130e8865cafSJohn Baldwin bzero(&tot, sizeof(tot)); 131e8865cafSJohn Baldwin KGET(NL_SWTAILQ, &swtailq); 132e8865cafSJohn Baldwin sp = TAILQ_FIRST(&swtailq); 133e8865cafSJohn Baldwin for (i = 0; sp != NULL; i++) { 134e8865cafSJohn Baldwin KGET2(sp, &swinfo, "swinfo"); 135e8865cafSJohn Baldwin ttl = swinfo.sw_nblks - dmmax; 136e8865cafSJohn Baldwin if (i < swap_max - 1) { 137e8865cafSJohn Baldwin bzero(&swap_ary[i], sizeof(swap_ary[i])); 138e8865cafSJohn Baldwin swap_ary[i].ksw_total = ttl; 139e8865cafSJohn Baldwin swap_ary[i].ksw_used = swinfo.sw_used; 140e8865cafSJohn Baldwin swap_ary[i].ksw_flags = swinfo.sw_flags; 141e8865cafSJohn Baldwin GETSWDEVNAME(swinfo.sw_dev, swap_ary[i].ksw_devname, 142e8865cafSJohn Baldwin flags); 143e8865cafSJohn Baldwin } 144e8865cafSJohn Baldwin tot.ksw_total += ttl; 145e8865cafSJohn Baldwin tot.ksw_used += swinfo.sw_used; 146e8865cafSJohn Baldwin sp = TAILQ_NEXT(&swinfo, sw_list); 147e8865cafSJohn Baldwin } 148e8865cafSJohn Baldwin 149e8865cafSJohn Baldwin if (i >= swap_max) 150e8865cafSJohn Baldwin i = swap_max - 1; 151e8865cafSJohn Baldwin if (i >= 0) 152e8865cafSJohn Baldwin swap_ary[i] = tot; 153e8865cafSJohn Baldwin 154e8865cafSJohn Baldwin return(i); 155e8865cafSJohn Baldwin } 156e8865cafSJohn Baldwin 157ae3a37adSRobert Watson #define GETSYSCTL(kd, name, var) \ 158ae3a37adSRobert Watson getsysctl(kd, name, &(var), sizeof(var)) 159e04a7c4aSThomas Moestl 160e04a7c4aSThomas Moestl /* The maximum MIB length for vm.swap_info and an additional device number */ 161e04a7c4aSThomas Moestl #define SWI_MAXMIB 3 162ae3a37adSRobert Watson 163ae3a37adSRobert Watson int 164ae3a37adSRobert Watson kvm_getswapinfo_sysctl( 165ae3a37adSRobert Watson kvm_t *kd, 166ae3a37adSRobert Watson struct kvm_swap *swap_ary, 167ae3a37adSRobert Watson int swap_max, 168ae3a37adSRobert Watson int flags 169ae3a37adSRobert Watson ) { 170e04a7c4aSThomas Moestl int ti, ttl; 171e04a7c4aSThomas Moestl size_t mibi, len; 172e04a7c4aSThomas Moestl int soid[SWI_MAXMIB]; 173e04a7c4aSThomas Moestl struct xswdev xsd; 174e04a7c4aSThomas Moestl struct kvm_swap tot; 175ae3a37adSRobert Watson 176ae3a37adSRobert Watson if (!GETSYSCTL(kd, "vm.dmmax", dmmax)) 177ae3a37adSRobert Watson return -1; 178ae3a37adSRobert Watson 179e04a7c4aSThomas Moestl mibi = SWI_MAXMIB - 1; 180e04a7c4aSThomas Moestl if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { 181e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "sysctlnametomib failed: %s", 182e04a7c4aSThomas Moestl strerror(errno)); 183e04a7c4aSThomas Moestl return -1; 184e04a7c4aSThomas Moestl } 185e04a7c4aSThomas Moestl bzero(&tot, sizeof(tot)); 186e04a7c4aSThomas Moestl for (unswdev = 0;; unswdev++) { 187e04a7c4aSThomas Moestl soid[mibi] = unswdev; 188e04a7c4aSThomas Moestl len = sizeof(xsd); 189e04a7c4aSThomas Moestl if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { 190e04a7c4aSThomas Moestl if (errno == ENOENT) 191e04a7c4aSThomas Moestl break; 192e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "cannot read sysctl: %s.", 193e04a7c4aSThomas Moestl strerror(errno)); 194e04a7c4aSThomas Moestl return -1; 195e04a7c4aSThomas Moestl } 196e04a7c4aSThomas Moestl if (len != sizeof(xsd)) { 197e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "struct xswdev has unexpected " 198e04a7c4aSThomas Moestl "size; kernel and libkvm out of sync?"); 199e04a7c4aSThomas Moestl return -1; 200e04a7c4aSThomas Moestl } 201e04a7c4aSThomas Moestl if (xsd.xsw_version != XSWDEV_VERSION) { 202e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "struct xswdev version " 203e04a7c4aSThomas Moestl "mismatch; kernel and libkvm out of sync?"); 204ae3a37adSRobert Watson return -1; 205ae3a37adSRobert Watson } 206ae3a37adSRobert Watson 207e04a7c4aSThomas Moestl ttl = xsd.xsw_nblks - dmmax; 208e04a7c4aSThomas Moestl if (unswdev < swap_max - 1) { 209e04a7c4aSThomas Moestl bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); 210e04a7c4aSThomas Moestl swap_ary[unswdev].ksw_total = ttl; 211e04a7c4aSThomas Moestl swap_ary[unswdev].ksw_used = xsd.xsw_used; 212e04a7c4aSThomas Moestl swap_ary[unswdev].ksw_flags = xsd.xsw_flags; 213e04a7c4aSThomas Moestl GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname, 214e04a7c4aSThomas Moestl flags); 215e04a7c4aSThomas Moestl } 216e04a7c4aSThomas Moestl tot.ksw_total += ttl; 217e04a7c4aSThomas Moestl tot.ksw_used += xsd.xsw_used; 218e04a7c4aSThomas Moestl } 219ae3a37adSRobert Watson 220e04a7c4aSThomas Moestl ti = unswdev; 221e04a7c4aSThomas Moestl if (ti >= swap_max) 222e04a7c4aSThomas Moestl ti = swap_max - 1; 223e04a7c4aSThomas Moestl if (ti >= 0) 224e04a7c4aSThomas Moestl swap_ary[ti] = tot; 225ae3a37adSRobert Watson 226ae3a37adSRobert Watson return(ti); 227ae3a37adSRobert Watson } 228ae3a37adSRobert Watson 229ae3a37adSRobert Watson static int 230e8865cafSJohn Baldwin nlist_init(kvm_t *kd) 231e8865cafSJohn Baldwin { 232e8865cafSJohn Baldwin TAILQ_HEAD(, swdevt) swtailq; 233e8865cafSJohn Baldwin struct swdevt *sp, swinfo; 234e8865cafSJohn Baldwin 235e8865cafSJohn Baldwin if (kvm_swap_nl_cached) 236e8865cafSJohn Baldwin return (1); 237e8865cafSJohn Baldwin 238e8865cafSJohn Baldwin if (kvm_nlist(kd, kvm_swap_nl) < 0) 239e8865cafSJohn Baldwin return (0); 240e8865cafSJohn Baldwin 241e8865cafSJohn Baldwin /* Required entries */ 242e8865cafSJohn Baldwin if (kvm_swap_nl[NL_SWTAILQ].n_value == 0) { 243e8865cafSJohn Baldwin _kvm_err(kd, kd->program, "unable to find swtailq"); 244e8865cafSJohn Baldwin return (0); 245e8865cafSJohn Baldwin } 246e8865cafSJohn Baldwin 247e8865cafSJohn Baldwin if (kvm_swap_nl[NL_DMMAX].n_value == 0) { 248e8865cafSJohn Baldwin _kvm_err(kd, kd->program, "unable to find dmmax"); 249e8865cafSJohn Baldwin return (0); 250e8865cafSJohn Baldwin } 251e8865cafSJohn Baldwin 252e8865cafSJohn Baldwin /* Get globals, type of swap */ 253e8865cafSJohn Baldwin KGET(NL_DMMAX, &dmmax); 254e8865cafSJohn Baldwin 255e8865cafSJohn Baldwin kvm_swap_nl_cached = 1; 256e8865cafSJohn Baldwin return (1); 257e8865cafSJohn Baldwin } 258e8865cafSJohn Baldwin 259e8865cafSJohn Baldwin static int 260ae3a37adSRobert Watson getsysctl ( 261ae3a37adSRobert Watson kvm_t *kd, 262ae3a37adSRobert Watson char *name, 263ae3a37adSRobert Watson void *ptr, 264e04a7c4aSThomas Moestl size_t len 265ae3a37adSRobert Watson ) { 266e04a7c4aSThomas Moestl size_t nlen = len; 267ae3a37adSRobert Watson if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 268e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name, 269e04a7c4aSThomas Moestl strerror(errno)); 270ae3a37adSRobert Watson return (0); 271ae3a37adSRobert Watson } 272ae3a37adSRobert Watson if (nlen != len) { 273ae3a37adSRobert Watson _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name); 274ae3a37adSRobert Watson return (0); 275ae3a37adSRobert Watson } 276ae3a37adSRobert Watson return (1); 277ae3a37adSRobert Watson } 278