1 /* 2 * Copyright (c) 1999, Matthew Dillon. All Rights Reserved. 3 * Copyright (c) 2001, Thomas Moestl. All Rights Reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/time.h> 32 #include <sys/stat.h> 33 #include <sys/blist.h> 34 #include <sys/sysctl.h> 35 36 #include <vm/vm_param.h> 37 38 #include <err.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <kvm.h> 42 #include <nlist.h> 43 #include <paths.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <limits.h> 49 50 #include "kvm_private.h" 51 52 #define NL_SWAPBLIST 0 53 #define NL_SWDEVT 1 54 #define NL_NSWDEV 2 55 #define NL_DMMAX 3 56 57 static int kvm_swap_nl_cached = 0; 58 static int unswdev; /* number of found swap dev's */ 59 static int dmmax; 60 61 static int kvm_getswapinfo_sysctl(kvm_t *, struct kvm_swap *, int, int); 62 static int getsysctl(kvm_t *, char *, void *, size_t); 63 64 #define GETSWDEVNAME(dev, str, flags) \ 65 if (dev == NODEV) { \ 66 strlcpy(str, "[NFS swap]", sizeof(str)); \ 67 } else { \ 68 snprintf( \ 69 str, sizeof(str),"%s%s", \ 70 ((flags & SWIF_DEV_PREFIX) ? _PATH_DEV : ""), \ 71 devname(dev, S_IFCHR) \ 72 ); \ 73 } 74 75 int 76 kvm_getswapinfo( 77 kvm_t *kd, 78 struct kvm_swap *swap_ary, 79 int swap_max, 80 int flags 81 ) { 82 83 /* 84 * clear cache 85 */ 86 if (kd == NULL) { 87 kvm_swap_nl_cached = 0; 88 return(0); 89 } 90 91 if (ISALIVE(kd)) { 92 return kvm_getswapinfo_sysctl(kd, swap_ary, swap_max, flags); 93 } else { 94 return -1; 95 } 96 } 97 98 #define GETSYSCTL(kd, name, var) \ 99 getsysctl(kd, name, &(var), sizeof(var)) 100 101 /* The maximum MIB length for vm.swap_info and an additional device number */ 102 #define SWI_MAXMIB 3 103 104 int 105 kvm_getswapinfo_sysctl( 106 kvm_t *kd, 107 struct kvm_swap *swap_ary, 108 int swap_max, 109 int flags 110 ) { 111 int ti, ttl; 112 size_t mibi, len; 113 int soid[SWI_MAXMIB]; 114 struct xswdev xsd; 115 struct kvm_swap tot; 116 117 if (!GETSYSCTL(kd, "vm.dmmax", dmmax)) 118 return -1; 119 120 mibi = SWI_MAXMIB - 1; 121 if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { 122 _kvm_err(kd, kd->program, "sysctlnametomib failed: %s", 123 strerror(errno)); 124 return -1; 125 } 126 bzero(&tot, sizeof(tot)); 127 for (unswdev = 0;; unswdev++) { 128 soid[mibi] = unswdev; 129 len = sizeof(xsd); 130 if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { 131 if (errno == ENOENT) 132 break; 133 _kvm_err(kd, kd->program, "cannot read sysctl: %s.", 134 strerror(errno)); 135 return -1; 136 } 137 if (len != sizeof(xsd)) { 138 _kvm_err(kd, kd->program, "struct xswdev has unexpected " 139 "size; kernel and libkvm out of sync?"); 140 return -1; 141 } 142 if (xsd.xsw_version != XSWDEV_VERSION) { 143 _kvm_err(kd, kd->program, "struct xswdev version " 144 "mismatch; kernel and libkvm out of sync?"); 145 return -1; 146 } 147 148 ttl = xsd.xsw_nblks - dmmax; 149 if (unswdev < swap_max - 1) { 150 bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); 151 swap_ary[unswdev].ksw_total = ttl; 152 swap_ary[unswdev].ksw_used = xsd.xsw_used; 153 swap_ary[unswdev].ksw_flags = xsd.xsw_flags; 154 GETSWDEVNAME(xsd.xsw_dev, swap_ary[unswdev].ksw_devname, 155 flags); 156 } 157 tot.ksw_total += ttl; 158 tot.ksw_used += xsd.xsw_used; 159 } 160 161 ti = unswdev; 162 if (ti >= swap_max) 163 ti = swap_max - 1; 164 if (ti >= 0) 165 swap_ary[ti] = tot; 166 167 return(ti); 168 } 169 170 static int 171 getsysctl ( 172 kvm_t *kd, 173 char *name, 174 void *ptr, 175 size_t len 176 ) { 177 size_t nlen = len; 178 if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { 179 _kvm_err(kd, kd->program, "cannot read sysctl %s:%s", name, 180 strerror(errno)); 181 return (0); 182 } 183 if (nlen != len) { 184 _kvm_err(kd, kd->program, "sysctl %s has unexpected size", name); 185 return (0); 186 } 187 return (1); 188 } 189