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