1 /* $NetBSD: swap.c,v 1.5 1996/05/10 23:16:38 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)swap.c 8.3 (Berkeley) 4/29/95"; 39 #endif 40 static char rcsid[] = "$NetBSD: swap.c,v 1.5 1996/05/10 23:16:38 thorpej Exp $"; 41 #endif /* not lint */ 42 43 /* 44 * swapinfo - based on a program of the same name by Kevin Lahey 45 */ 46 47 #include <sys/param.h> 48 #include <sys/buf.h> 49 #include <sys/conf.h> 50 #include <sys/ioctl.h> 51 #include <sys/map.h> 52 #include <sys/stat.h> 53 54 #include <kvm.h> 55 #include <nlist.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 61 #include "systat.h" 62 #include "extern.h" 63 64 extern char *getbsize __P((int *headerlenp, long *blocksizep)); 65 void showspace __P((char *header, int hlen, long blocksize)); 66 67 struct nlist syms[] = { 68 { "_swapmap" }, /* list of free swap areas */ 69 #define VM_SWAPMAP 0 70 { "_nswapmap" },/* size of the swap map */ 71 #define VM_NSWAPMAP 1 72 { "_swdevt" }, /* list of swap devices and sizes */ 73 #define VM_SWDEVT 2 74 { "_nswap" }, /* size of largest swap device */ 75 #define VM_NSWAP 3 76 { "_nswdev" }, /* number of swap devices */ 77 #define VM_NSWDEV 4 78 { "_dmmax" }, /* maximum size of a swap block */ 79 #define VM_DMMAX 5 80 0 81 }; 82 83 static int nswap, nswdev, dmmax, nswapmap; 84 static struct swdevt *sw; 85 static long *perdev, blocksize; 86 static struct map *swapmap, *kswapmap; 87 static struct mapent *mp; 88 static int nfree, hlen; 89 90 #define SVAR(var) __STRING(var) /* to force expansion */ 91 #define KGET(idx, var) \ 92 KGET1(idx, &var, sizeof(var), SVAR(var)) 93 #define KGET1(idx, p, s, msg) \ 94 KGET2(syms[idx].n_value, p, s, msg) 95 #define KGET2(addr, p, s, msg) \ 96 if (kvm_read(kd, addr, p, s) != s) { \ 97 error("cannot read %s: %s", msg, kvm_geterr(kd)); \ 98 return (0); \ 99 } 100 101 WINDOW * 102 openswap() 103 { 104 return (subwin(stdscr, LINES-5-1, 0, 5, 0)); 105 } 106 107 void 108 closeswap(w) 109 WINDOW *w; 110 { 111 if (w == NULL) 112 return; 113 wclear(w); 114 wrefresh(w); 115 delwin(w); 116 } 117 118 initswap() 119 { 120 int i; 121 char msgbuf[BUFSIZ]; 122 static int once = 0; 123 124 if (once) 125 return (1); 126 if (kvm_nlist(kd, syms)) { 127 strcpy(msgbuf, "systat: swap: cannot find"); 128 for (i = 0; syms[i].n_name != NULL; i++) { 129 if (syms[i].n_value == 0) { 130 strcat(msgbuf, " "); 131 strcat(msgbuf, syms[i].n_name); 132 } 133 } 134 error(msgbuf); 135 return (0); 136 } 137 KGET(VM_NSWAP, nswap); 138 KGET(VM_NSWDEV, nswdev); 139 KGET(VM_DMMAX, dmmax); 140 KGET(VM_NSWAPMAP, nswapmap); 141 KGET(VM_SWAPMAP, kswapmap); /* kernel `swapmap' is a pointer */ 142 if ((sw = malloc(nswdev * sizeof(*sw))) == NULL || 143 (perdev = malloc(nswdev * sizeof(*perdev))) == NULL || 144 (mp = malloc(nswapmap * sizeof(*mp))) == NULL) { 145 error("swap malloc"); 146 return (0); 147 } 148 KGET1(VM_SWDEVT, sw, nswdev * sizeof(*sw), "swdevt"); 149 once = 1; 150 return (1); 151 } 152 153 void 154 fetchswap() 155 { 156 int s, e, i; 157 158 s = nswapmap * sizeof(*mp); 159 if (kvm_read(kd, (long)kswapmap, mp, s) != s) 160 error("cannot read swapmap: %s", kvm_geterr(kd)); 161 162 /* first entry in map is `struct map'; rest are mapent's */ 163 swapmap = (struct map *)mp; 164 if (nswapmap != swapmap->m_limit - (struct mapent *)kswapmap) 165 error("panic: swap: nswapmap goof"); 166 167 /* 168 * Count up swap space. 169 */ 170 nfree = 0; 171 bzero(perdev, nswdev * sizeof(*perdev)); 172 for (mp++; mp->m_addr != 0; mp++) { 173 s = mp->m_addr; /* start of swap region */ 174 e = mp->m_addr + mp->m_size; /* end of region */ 175 nfree += mp->m_size; 176 177 /* 178 * Swap space is split up among the configured disks. 179 * The first dmmax blocks of swap space some from the 180 * first disk, the next dmmax blocks from the next, 181 * and so on. The list of free space joins adjacent 182 * free blocks, ignoring device boundries. If we want 183 * to keep track of this information per device, we'll 184 * just have to extract it ourselves. 185 */ 186 187 /* calculate first device on which this falls */ 188 i = (s / dmmax) % nswdev; 189 while (s < e) { /* XXX this is inefficient */ 190 int bound = roundup(s + 1, dmmax); 191 192 if (bound > e) 193 bound = e; 194 perdev[i] += bound - s; 195 if (++i >= nswdev) 196 i = 0; 197 s = bound; 198 } 199 } 200 } 201 202 void 203 labelswap() 204 { 205 char *header, *p; 206 int row, i; 207 208 row = 0; 209 wmove(wnd, row, 0); wclrtobot(wnd); 210 header = getbsize(&hlen, &blocksize); 211 mvwprintw(wnd, row++, 0, "%-5s%*s%9s %55s", 212 "Disk", hlen, header, "Used", 213 "/0% /10% /20% /30% /40% /50% /60% /70% /80% /90% /100%"); 214 for (i = 0; i < nswdev; i++) { 215 p = devname(sw[i].sw_dev, S_IFBLK); 216 mvwprintw(wnd, i + 1, 0, "%-5s", p == NULL ? "??" : p); 217 } 218 } 219 220 void 221 showswap() 222 { 223 int col, row, div, i, j, avail, npfree, used, xsize, xfree; 224 225 div = blocksize / 512; 226 avail = npfree = 0; 227 for (i = 0; i < nswdev; i++) { 228 col = 5; 229 mvwprintw(wnd, i + 1, col, "%*d", hlen, sw[i].sw_nblks / div); 230 col += hlen; 231 /* 232 * Don't report statistics for partitions which have not 233 * yet been activated via swapon(8). 234 */ 235 if (!sw[i].sw_freed) { 236 mvwprintw(wnd, i + 1, col + 8, 237 "0 *** not available for swapping ***"); 238 continue; 239 } 240 xsize = sw[i].sw_nblks; 241 xfree = perdev[i]; 242 used = xsize - xfree; 243 mvwprintw(wnd, i + 1, col, "%9d ", used / div); 244 for (j = (100 * used / xsize + 1) / 2; j > 0; j--) 245 waddch(wnd, 'X'); 246 npfree++; 247 avail += xsize; 248 } 249 /* 250 * If only one partition has been set up via swapon(8), we don't 251 * need to bother with totals. 252 */ 253 if (npfree > 1) { 254 used = avail - nfree; 255 mvwprintw(wnd, i + 1, 0, "%-5s%*d%9d ", 256 "Total", hlen, avail / div, used / div); 257 for (j = (100 * used / avail + 1) / 2; j > 0; j--) 258 waddch(wnd, 'X'); 259 } 260 } 261