swapinfo(1) command from 1.1.5. This version has been modified to work

with the new libkvm interfaces.
This commit is contained in:
David Greenman 1994-08-12 01:49:30 +00:00
parent 40460a7a82
commit e6692375a2
5 changed files with 406 additions and 0 deletions

View File

@ -0,0 +1,13 @@
# @(#)Makefile 5.5 (Berkeley) 4/23/91
PROG= swapinfo
SRCS= swapinfo.c devname.c # getbsize.c
.PATH: ${.CURDIR}/../../bin/df
CFLAGS= -g
DPADD= ${LIBMATH} ${LIBUTIL}
LDADD= -lm -lkvm
BINGRP= kmem
BINMODE=2555
.include <bsd.prog.mk>

38
usr.sbin/swapinfo/README Normal file
View File

@ -0,0 +1,38 @@
swapinfo
========
Swapinfo is designed to provide some information to the user about the
state of the swap space on the system. I've written it based on a
brief (!) perusal of the VM code in 386BSD. I could be pretty confused
about how it all fits together, and perhaps this is totally bogus.
It seems to work for me, though.
How it works:
During startup, the system traverses the list of configured swap partitions,
and determines the size of the various partitions. As each new partition
is added for swapping (via swapon), the free space on that disk is added
to a linked list of free space. Adjacent areas are coalesced to form
larger areas. The swapping algorithm seems to take the first free section
that it finds [?].
Swapinfo reads in the list of configured swap partitions from the /dev/kmem,
to determine the size of the partitions. It then traverses the list
of free space, figuring up how much is still available and how much
has therefore been used. Things get a little hairy in that the swap space
is divided amongst the configured swap partitions so that the first
4096 blocks of swap go on the first swap partition, the second 4096 on
the second swap partition, and so on. This works out to be a fairly
simple bit of code, though.
More caveats:
This works on my system. Your milage may vary. Since I'm reading /dev/kmem
to follow a linked list, the program could easily get lost looking for
some free space if anything got changed between reads of /dev/kmem.
If you get occasional inconsistant results, ignore 'em.
Feel free to send bug reports, flames, etc., to:
Kevin Lahey
kml@rokkaku.atl.ga.us

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)devname.c 5.14 (Berkeley) 5/6/91";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <fcntl.h>
#include <db.h>
#include <stdio.h>
#include <paths.h>
char *
devname(dev, type)
dev_t dev;
mode_t type;
{
struct {
mode_t type;
dev_t dev;
} bkey;
static DB *db;
static int failure;
DBT data, key;
if (!db && !failure &&
!(db = dbopen(_PATH_DEVDB, O_RDONLY, 0, DB_HASH, NULL))) {
(void)fprintf(stderr,
"warning: no device database %s\n", _PATH_DEVDB);
failure = 1;
}
if (failure)
return("??");
/*
* Keys are a mode_t followed by a dev_t. The former is the type of
* the file (mode & S_IFMT), the latter is the st_rdev field.
*/
bkey.dev = dev;
bkey.type = type;
key.data = &bkey;
key.size = sizeof(bkey);
return((db->get)(db, &key, &data, 0L) ? "??" : (char *)data.data);
}

View File

@ -0,0 +1,53 @@
.\"
.\" swapinfo
.\"
.Dd February 23, 1993
.Dt SWAPINFO 1
.Sh NAME
.Nm swapinfo
.Nd display free swap space
.Sh SYNOPSIS
.Nm swapinfo
.Op Fl k
.Sh DESCRIPTION
.Nm Swapinfo
displays statistics about the amount of free swap space on all of the
swap areas compiled into the kernel.
.Pp
The following options are available:
.Bl -tag -width Ds
.It Fl k
By default, all sizes are reported in 512-byte block counts.
The
.Fl k
option causes the numbers to be reported in kilobyte counts.
.El
.Sh STATISTICS
Statistics are reported for all swap partitions configured into the kernel.
The first column is the device name of the partition. The next column is
the total space available in the partition. The
.Ar Used
column indicates the total blocks used so far; the
.Ar Available
column indicates how much space is remaining on each partition.
The
.Ar Capacity
reports the percentage of space used.
.Pp
If more than one partition is configured into the system, totals for all
of the statistics will be reported in the final line of the report.
.Sh "BUGS AND CAVEATS"
The information reported by
.Nm swapinfo
is stored in the kernel in a linked list. Since we are merely reading
this list out of kernel memory, it is entirely possible that the list could
change as we try to read it. Suspicious and unrepeatable values are probably
incorrect.
.Pp
Statistics are reported for all swap partitions compiled into the kernel,
regardless of whether those partitions are being used.
.Sh AUTHOR
.RS
Kevin Lahey
.br
kml@rokkaku.atl.ga.us

View File

@ -0,0 +1,227 @@
/*
* swapinfo
*
* Swapinfo will provide some information about the state of the swap
* space for the system. It'll determine the number of swap areas,
* their original size, and their utilization.
*
* Kevin Lahey, February 16, 1993
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/termios.h>
#include <sys/stat.h>
#include <sys/tty.h>
#include <sys/uio.h>
#include <sys/buf.h>
#include <sys/conf.h>
#include <sys/rlist.h>
#include <nlist.h>
#include <kvm.h>
struct rlist *swapmap;
static struct nlist nl[] = {{"_swapmap"}, /* list of free swap areas */
#define VM_SWAPMAP 0
{"_swdevt"}, /* list of swap devices and sizes */
#define VM_SWDEVT 1
{"_nswap"}, /* size of largest swap device */
#define VM_NSWAP 2
{"_nswdev"}, /* number of swap devices */
#define VM_NSWDEV 3
{"_dmmax"}, /* maximum size of a swap block */
#define VM_DMMAX 4
{""}};
char *getbsize __P((int *, long *));
void usage __P((void));
int kflag;
main (argc, argv)
int argc;
char **argv;
{
int i, total_avail, total_free, total_partitions, *by_device,
nswap, nswdev, dmmax, ch;
struct swdevt *swdevt;
struct rlist head;
static long blocksize;
static int headerlen;
static char *header;
char **save;
kvm_t *kd;
/* We are trying to be simple here: */
save = argv;
kflag = 0;
while ((ch = getopt(argc, argv, "k")) != EOF)
switch(ch) {
case 'k':
kflag = 1;
break;
case '?':
default:
usage();
}
argv += optind;
if (!*argv) {
argv = save;
argv[0] = ".";
argv[1] = NULL;
}
/* Open up /dev/kmem for reading. */
if ((kd = kvm_openfiles(NULL, NULL, NULL, NULL, NULL)) == (kvm_t *)0) {
fprintf (stderr, "%s: kvm_openfiles: %s\n",
argv [0], kvm_geterr(kd));
exit (1);
}
/* Figure out the offset of the various structures we'll need. */
if (kvm_nlist(kd, nl) == -1) {
fprintf (stderr, "%s: kvm_nlist: %s\n",
argv [0], kvm_geterr(kd));
exit (1);
}
if (kvm_read(kd, nl[VM_NSWAP].n_value, &nswap, sizeof (nswap)) !=
sizeof (nswap)) {
fprintf (stderr, "%s: didn't read all of nswap\n",
argv [0]);
exit (5);
}
if (kvm_read(kd, nl[VM_NSWDEV].n_value, &nswdev, sizeof (nswdev)) !=
sizeof (nswdev)) {
fprintf (stderr, "%s: didn't read all of nswdev\n",
argv [0]);
exit (5);
}
if (kvm_read(kd, nl[VM_DMMAX].n_value, &dmmax, sizeof (dmmax)) !=
sizeof (dmmax)) {
fprintf (stderr, "%s: didn't read all of dmmax\n",
argv [0]);
exit (5);
}
if ((swdevt = malloc (sizeof (struct swdevt) * nswdev)) == NULL ||
(by_device = calloc (sizeof (*by_device), nswdev)) == NULL) {
perror ("malloc");
exit (5);
}
if (kvm_read(kd, nl[VM_SWDEVT].n_value, swdevt,
sizeof (struct swdevt) * nswdev) !=
sizeof (struct swdevt) * nswdev) {
fprintf (stderr, "%s: didn't read all of swdevt\n",
argv [0]);
exit (5);
}
if (kvm_read(kd, nl[0].n_value, &swapmap, sizeof (struct rlist *)) !=
sizeof (struct rlist *)) {
fprintf (stderr, "%s: didn't read all of swapmap\n",
argv [0]);
exit (5);
}
/* Traverse the list of free swap space... */
total_free = 0;
while (swapmap) {
int top, bottom, next_block;
if (kvm_read(kd, (long) swapmap, &head, sizeof (struct rlist )) !=
sizeof (struct rlist )) {
fprintf (stderr, "%s: didn't read all of head\n",
argv [0]);
exit (5);
}
top = head.rl_end;
bottom = head.rl_start;
total_free += top - bottom + 1;
/*
* Swap space is split up among the configured disk.
* The first dmmax blocks of swap space some from the
* first disk, the next dmmax blocks from the next,
* and so on. The list of free space joins adjacent
* free blocks, ignoring device boundries. If we want
* to keep track of this information per device, we'll
* just have to extract it ourselves.
*/
while (top / dmmax != bottom / dmmax) {
next_block = ((bottom + dmmax) / dmmax);
by_device [(bottom / dmmax) % nswdev] +=
next_block * dmmax - bottom;
bottom = next_block * dmmax;
}
by_device [(bottom / dmmax) % nswdev] +=
top - bottom + 1;
swapmap = head.rl_next;
}
header = getbsize(&headerlen, &blocksize);
printf ("%-10s %10s %10s %10s %10s\n",
"Device", header, "Used", "Available", "Capacity");
for (total_avail = total_partitions = i = 0; i < nswdev; i++) {
printf ("/dev/%-5s %10d ",
devname (swdevt [i].sw_dev, S_IFBLK),
swdevt [i].sw_nblks / (blocksize/512));
/*
* Don't report statistics for partitions which have not
* yet been activated via swapon(8).
*/
if (!swdevt [i].sw_freed) {
printf (" *** not available for swapping ***\n");
} else {
total_partitions++;
total_avail += swdevt [i].sw_nblks;
printf ("%10d %10d %7.0f%%\n",
(swdevt [i].sw_nblks - by_device [i]) / (blocksize/512),
by_device [i] / (blocksize/512),
(double) (swdevt [i].sw_nblks -
by_device [i]) /
(double) swdevt [i].sw_nblks * 100.0);
}
}
/*
* If only one partition has been set up via swapon(8), we don't
* need to bother with totals.
*/
if (total_partitions > 1)
printf ("%-10s %10d %10d %10d %7.0f%%\n", "Total",
total_avail / (blocksize/512),
(total_avail - total_free) / (blocksize/512),
total_free / (blocksize/512),
(double) (total_avail - total_free) /
(double) total_avail * 100.0);
exit (0);
}
void
usage()
{
(void)fprintf(stderr, "usage: swapinfo [-k]\n");
exit(1);
}