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