1*5e53a4f9SPedro F. Giffuni /*- 2*5e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*5e53a4f9SPedro F. Giffuni * 4e92324a2SMatthew Dillon * Copyright (c) 1999, Matthew Dillon. All Rights Reserved. 59e749cc9SWarner Losh * Copyright (c) 2001, Thomas Moestl. All Rights Reserved. 6e92324a2SMatthew Dillon * 7e92324a2SMatthew Dillon * Redistribution and use in source and binary forms, with or without 89e749cc9SWarner Losh * modification, are permitted provided that the following conditions 99e749cc9SWarner Losh * are met: 109e749cc9SWarner Losh * 1. Redistributions of source code must retain the above copyright 119e749cc9SWarner Losh * notice, this list of conditions and the following disclaimer. 129e749cc9SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 139e749cc9SWarner Losh * notice, this list of conditions and the following disclaimer in the 149e749cc9SWarner Losh * documentation and/or other materials provided with the distribution. 159e749cc9SWarner Losh * 169e749cc9SWarner Losh * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 179e749cc9SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 189e749cc9SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 199e749cc9SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 209e749cc9SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 219e749cc9SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 229e749cc9SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 239e749cc9SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 249e749cc9SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 259e749cc9SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 269e749cc9SWarner Losh * SUCH DAMAGE. 27e92324a2SMatthew Dillon */ 28e92324a2SMatthew Dillon 29e67f5b9fSMatthew Dillon #include <sys/cdefs.h> 30e67f5b9fSMatthew Dillon __FBSDID("$FreeBSD$"); 31e92324a2SMatthew Dillon 32e92324a2SMatthew Dillon #include <sys/param.h> 33e92324a2SMatthew Dillon #include <sys/time.h> 34e92324a2SMatthew Dillon #include <sys/stat.h> 35e92324a2SMatthew Dillon #include <sys/blist.h> 36ae3a37adSRobert Watson #include <sys/sysctl.h> 37e92324a2SMatthew Dillon 38e8865cafSJohn Baldwin #include <vm/swap_pager.h> 39e04a7c4aSThomas Moestl #include <vm/vm_param.h> 40e04a7c4aSThomas Moestl 41e92324a2SMatthew Dillon #include <err.h> 42e04a7c4aSThomas Moestl #include <errno.h> 43e92324a2SMatthew Dillon #include <fcntl.h> 44e92324a2SMatthew Dillon #include <kvm.h> 45e92324a2SMatthew Dillon #include <nlist.h> 461a37aa56SDavid E. O'Brien #include <paths.h> 47e92324a2SMatthew Dillon #include <stdio.h> 48e92324a2SMatthew Dillon #include <stdlib.h> 49e92324a2SMatthew Dillon #include <string.h> 50e92324a2SMatthew Dillon #include <unistd.h> 51ae3a37adSRobert Watson #include <limits.h> 52ae3a37adSRobert Watson 53ae3a37adSRobert Watson #include "kvm_private.h" 54e92324a2SMatthew Dillon 55e8865cafSJohn Baldwin static struct nlist kvm_swap_nl[] = { 56c10970ddSUlrich Spörlein { .n_name = "_swtailq" }, /* list of swap devices and sizes */ 57c10970ddSUlrich Spörlein { .n_name = "_dmmax" }, /* maximum size of a swap block */ 58c10970ddSUlrich Spörlein { .n_name = NULL } 59e8865cafSJohn Baldwin }; 60e8865cafSJohn Baldwin 61e8865cafSJohn Baldwin #define NL_SWTAILQ 0 62e8865cafSJohn Baldwin #define NL_DMMAX 1 63e92324a2SMatthew Dillon 64e92324a2SMatthew Dillon static int kvm_swap_nl_cached = 0; 65ae3a37adSRobert Watson static int unswdev; /* number of found swap dev's */ 66e92324a2SMatthew Dillon static int dmmax; 67e92324a2SMatthew Dillon 68e8865cafSJohn Baldwin static int kvm_getswapinfo_kvm(kvm_t *, struct kvm_swap *, int, int); 69ae3a37adSRobert Watson static int kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int); 70e8865cafSJohn Baldwin static int nlist_init(kvm_t *); 71c10970ddSUlrich Spörlein static int getsysctl(kvm_t *, const char *, void *, size_t); 72e92324a2SMatthew Dillon 73e8865cafSJohn Baldwin #define KREAD(kd, addr, obj) \ 74e8865cafSJohn Baldwin (kvm_read(kd, addr, (char *)(obj), sizeof(*obj)) != sizeof(*obj)) 75e8865cafSJohn Baldwin #define KGET(idx, var) \ 76e8865cafSJohn Baldwin KGET2(kvm_swap_nl[(idx)].n_value, var, kvm_swap_nl[(idx)].n_name) 77e8865cafSJohn Baldwin #define KGET2(addr, var, msg) \ 78e8865cafSJohn Baldwin if (KREAD(kd, (u_long)(addr), (var))) { \ 79e8865cafSJohn Baldwin _kvm_err(kd, kd->program, "cannot read %s", msg); \ 80e8865cafSJohn Baldwin return (-1); \ 81e8865cafSJohn Baldwin } 82e8865cafSJohn Baldwin 83ae3a37adSRobert Watson #define GETSWDEVNAME(dev, str, flags) \ 84ae3a37adSRobert Watson if (dev == NODEV) { \ 85ae3a37adSRobert Watson strlcpy(str, "[NFS swap]", sizeof(str)); \ 86ae3a37adSRobert Watson } else { \ 87ae3a37adSRobert Watson snprintf( \ 88ae3a37adSRobert Watson str, sizeof(str),"%s%s", \ 89ae3a37adSRobert Watson ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \ 90ae3a37adSRobert Watson devname(dev, S_IFCHR) \ 91ae3a37adSRobert Watson ); \ 92ae3a37adSRobert Watson } 93ae3a37adSRobert Watson 94e92324a2SMatthew Dillon int 95c10970ddSUlrich Spörlein kvm_getswapinfo(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, int flags) 96c10970ddSUlrich Spörlein { 97e92324a2SMatthew Dillon 98e92324a2SMatthew Dillon /* 99e92324a2SMatthew Dillon * clear cache 100e92324a2SMatthew Dillon */ 101e92324a2SMatthew Dillon if (kd == NULL) { 102e92324a2SMatthew Dillon kvm_swap_nl_cached = 0; 103e92324a2SMatthew Dillon return(0); 104e92324a2SMatthew Dillon } 105e92324a2SMatthew Dillon 106ae3a37adSRobert Watson if (ISALIVE(kd)) { 107ae3a37adSRobert Watson return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags); 108ae3a37adSRobert Watson } else { 109e8865cafSJohn Baldwin return kvm_getswapinfo_kvm(kd, swap_ary, swap_max, flags); 110ae3a37adSRobert Watson } 111ae3a37adSRobert Watson } 112ae3a37adSRobert Watson 113e8865cafSJohn Baldwin int 114c10970ddSUlrich Spörlein kvm_getswapinfo_kvm(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, 115c10970ddSUlrich Spörlein int flags) 116c10970ddSUlrich Spörlein { 117eca80cd0SPedro F. Giffuni int i; 118eca80cd0SPedro F. Giffuni swblk_t ttl; 119e8865cafSJohn Baldwin TAILQ_HEAD(, swdevt) swtailq; 120e8865cafSJohn Baldwin struct swdevt *sp, swinfo; 121e8865cafSJohn Baldwin struct kvm_swap tot; 122e8865cafSJohn Baldwin 1237f911abeSJohn Baldwin if (!kd->arch->ka_native(kd)) { 1247f911abeSJohn Baldwin _kvm_err(kd, kd->program, 1257f911abeSJohn Baldwin "cannot read swapinfo from non-native core"); 1267f911abeSJohn Baldwin return (-1); 1277f911abeSJohn Baldwin } 1287f911abeSJohn Baldwin 129e8865cafSJohn Baldwin if (!nlist_init(kd)) 130e8865cafSJohn Baldwin return (-1); 131e8865cafSJohn Baldwin 132e8865cafSJohn Baldwin bzero(&tot, sizeof(tot)); 133e8865cafSJohn Baldwin KGET(NL_SWTAILQ, &swtailq); 134e8865cafSJohn Baldwin sp = TAILQ_FIRST(&swtailq); 135e8865cafSJohn Baldwin for (i = 0; sp != NULL; i++) { 136e8865cafSJohn Baldwin KGET2(sp, &swinfo, "swinfo"); 137e8865cafSJohn Baldwin ttl = swinfo.sw_nblks - dmmax; 138e8865cafSJohn Baldwin if (i < swap_max - 1) { 139e8865cafSJohn Baldwin bzero(&swap_ary[i], sizeof(swap_ary[i])); 140e8865cafSJohn Baldwin swap_ary[i].ksw_total = ttl; 141e8865cafSJohn Baldwin swap_ary[i].ksw_used = swinfo.sw_used; 142e8865cafSJohn Baldwin swap_ary[i].ksw_flags = swinfo.sw_flags; 143e8865cafSJohn Baldwin GETSWDEVNAME(swinfo.sw_dev, swap_ary[i].ksw_devname, 144e8865cafSJohn Baldwin flags); 145e8865cafSJohn Baldwin } 146e8865cafSJohn Baldwin tot.ksw_total += ttl; 147e8865cafSJohn Baldwin tot.ksw_used += swinfo.sw_used; 148e8865cafSJohn Baldwin sp = TAILQ_NEXT(&swinfo, sw_list); 149e8865cafSJohn Baldwin } 150e8865cafSJohn Baldwin 151e8865cafSJohn Baldwin if (i >= swap_max) 152e8865cafSJohn Baldwin i = swap_max - 1; 153e8865cafSJohn Baldwin if (i >= 0) 154e8865cafSJohn Baldwin swap_ary[i] = tot; 155e8865cafSJohn Baldwin 156e8865cafSJohn Baldwin return(i); 157e8865cafSJohn Baldwin } 158e8865cafSJohn Baldwin 159ae3a37adSRobert Watson #define GETSYSCTL(kd, name, var) \ 160ae3a37adSRobert Watson getsysctl(kd, name, &(var), sizeof(var)) 161e04a7c4aSThomas Moestl 162e04a7c4aSThomas Moestl /* The maximum MIB length for vm.swap_info and an additional device number */ 163e04a7c4aSThomas Moestl #define SWI_MAXMIB 3 164ae3a37adSRobert Watson 165ae3a37adSRobert Watson int 166c10970ddSUlrich Spörlein kvm_getswapinfo_sysctl(kvm_t *kd, struct kvm_swap *swap_ary, int swap_max, 167c10970ddSUlrich Spörlein int flags) 168c10970ddSUlrich Spörlein { 169eca80cd0SPedro F. Giffuni int ti; 170eca80cd0SPedro F. Giffuni swblk_t 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 233e8865cafSJohn Baldwin if (kvm_swap_nl_cached) 234e8865cafSJohn Baldwin return (1); 235e8865cafSJohn Baldwin 236e8865cafSJohn Baldwin if (kvm_nlist(kd, kvm_swap_nl) < 0) 237e8865cafSJohn Baldwin return (0); 238e8865cafSJohn Baldwin 239e8865cafSJohn Baldwin /* Required entries */ 240e8865cafSJohn Baldwin if (kvm_swap_nl[NL_SWTAILQ].n_value == 0) { 241e8865cafSJohn Baldwin _kvm_err(kd, kd->program, "unable to find swtailq"); 242e8865cafSJohn Baldwin return (0); 243e8865cafSJohn Baldwin } 244e8865cafSJohn Baldwin 245e8865cafSJohn Baldwin if (kvm_swap_nl[NL_DMMAX].n_value == 0) { 246e8865cafSJohn Baldwin _kvm_err(kd, kd->program, "unable to find dmmax"); 247e8865cafSJohn Baldwin return (0); 248e8865cafSJohn Baldwin } 249e8865cafSJohn Baldwin 250e8865cafSJohn Baldwin /* Get globals, type of swap */ 251e8865cafSJohn Baldwin KGET(NL_DMMAX, &dmmax); 252e8865cafSJohn Baldwin 253e8865cafSJohn Baldwin kvm_swap_nl_cached = 1; 254e8865cafSJohn Baldwin return (1); 255e8865cafSJohn Baldwin } 256e8865cafSJohn Baldwin 257e8865cafSJohn Baldwin static int 258c10970ddSUlrich Spörlein getsysctl(kvm_t *kd, const char *name, void *ptr, size_t len) 259c10970ddSUlrich Spörlein { 260e04a7c4aSThomas Moestl size_t nlen = len; 261ae3a37adSRobert Watson if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 262e04a7c4aSThomas Moestl _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name, 263e04a7c4aSThomas Moestl strerror(errno)); 264ae3a37adSRobert Watson return (0); 265ae3a37adSRobert Watson } 266ae3a37adSRobert Watson if (nlen != len) { 267ae3a37adSRobert Watson _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name); 268ae3a37adSRobert Watson return (0); 269ae3a37adSRobert Watson } 270ae3a37adSRobert Watson return (1); 271ae3a37adSRobert Watson } 272