Blame sysdeps/bsd/swap.c

Packit d37888
/* Copyright (C) 1998-99 Martin Baulig
Packit d37888
   This file is part of LibGTop 1.0.
Packit d37888
Packit d37888
   Contributed by Martin Baulig <martin@home-of-linux.org>, April 1998.
Packit d37888
Packit d37888
   LibGTop is free software; you can redistribute it and/or modify it
Packit d37888
   under the terms of the GNU General Public License as published by
Packit d37888
   the Free Software Foundation; either version 2 of the License,
Packit d37888
   or (at your option) any later version.
Packit d37888
Packit d37888
   LibGTop is distributed in the hope that it will be useful, but WITHOUT
Packit d37888
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
Packit d37888
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit d37888
   for more details.
Packit d37888
Packit d37888
   You should have received a copy of the GNU General Public License
Packit d37888
   along with LibGTop; see the file COPYING. If not, write to the
Packit d37888
   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit d37888
   Boston, MA 02110-1301, USA.
Packit d37888
*/
Packit d37888
Packit d37888
#include <config.h>
Packit d37888
#include <glibtop.h>
Packit d37888
#include <glibtop/error.h>
Packit d37888
#include <glibtop/swap.h>
Packit d37888
Packit d37888
#include <glibtop_suid.h>
Packit d37888
Packit d37888
static const unsigned long _glibtop_sysdeps_swap =
Packit d37888
(1L << GLIBTOP_SWAP_TOTAL) + (1L << GLIBTOP_SWAP_USED) +
Packit d37888
(1L << GLIBTOP_SWAP_FREE) + (1L << GLIBTOP_SWAP_PAGEIN) +
Packit d37888
(1L << GLIBTOP_SWAP_PAGEOUT);
Packit d37888
Packit d37888
#if defined(__FreeBSD__) || defined(__bsdi__) || defined(__FreeBSD_kernel__)
Packit d37888
Packit d37888
#include <sys/conf.h>
Packit d37888
#ifdef __bsdi__
Packit d37888
#include <vm/swap_pager.h>
Packit d37888
#else
Packit d37888
#if (__FreeBSD_version < 400005) && !defined(__FreeBSD_kernel__)
Packit d37888
#include <sys/rlist.h>
Packit d37888
#endif
Packit d37888
#endif
Packit d37888
#include <sys/vmmeter.h>
Packit d37888
Packit d37888
/* nlist structure for kernel access */
Packit d37888
Packit d37888
#if defined(__bsdi__)
Packit d37888
static struct nlist nlst [] = {
Packit d37888
	{ "_swapstats" }, /* general swap info */
Packit d37888
	{ 0 }
Packit d37888
};
Packit d37888
#elif __FreeBSD__ < 4
Packit d37888
static struct nlist nlst [] = {
Packit d37888
#define VM_SWAPLIST	0
Packit d37888
	{ "_swaplist" },/* list of free swap areas */
Packit d37888
#define VM_SWDEVT	1
Packit d37888
	{ "_swdevt" },	/* list of swap devices and sizes */
Packit d37888
#define VM_NSWAP	2
Packit d37888
	{ "_nswap" },	/* size of largest swap device */
Packit d37888
#define VM_NSWDEV	3
Packit d37888
	{ "_nswdev" },	/* number of swap devices */
Packit d37888
#define VM_DMMAX	4
Packit d37888
	{ "_dmmax" },	/* maximum size of a swap block */
Packit d37888
	{ 0 }
Packit d37888
};
Packit d37888
#endif
Packit d37888
Packit d37888
#elif defined(__NetBSD__) || defined(__OpenBSD__)
Packit d37888
Packit d37888
#if (__NetBSD_Version__ >= 104000000) || defined(__OpenBSD__)
Packit d37888
#include <uvm/uvm_extern.h>
Packit d37888
#include <sys/swap.h>
Packit d37888
#else
Packit d37888
#include <vm/vm_swap.h>
Packit d37888
#endif
Packit d37888
Packit d37888
#endif
Packit d37888
Packit d37888
#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) || defined(__OpenBSD__)
Packit d37888
static int mib_uvmexp [] = { CTL_VM, VM_UVMEXP };
Packit d37888
#else
Packit d37888
/* nlist structure for kernel access */
Packit d37888
static struct nlist nlst2 [] = {
Packit d37888
	{ "_cnt" },
Packit d37888
	{ 0 }
Packit d37888
};
Packit d37888
#endif
Packit d37888
Packit d37888
/* Init function. */
Packit d37888
Packit d37888
void
Packit d37888
_glibtop_init_swap_p (glibtop *server)
Packit d37888
{
Packit d37888
#if defined(__FreeBSD__) || defined(__bsdi__) || defined(__FreeBSD_kernel__)
Packit d37888
#if __FreeBSD__ < 4 || defined(__bsdi__)
Packit d37888
	if (kvm_nlist (server->machine->kd, nlst) < 0) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_nlist (swap)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
#else
Packit d37888
	struct kvm_swap dummy;
Packit d37888
Packit d37888
	if (kvm_getswapinfo (server->machine->kd, &dummy, 1, 0) != 0) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_swap (swap)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
#endif
Packit d37888
#endif
Packit d37888
Packit d37888
#if !(defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)) && !defined(__OpenBSD__)
Packit d37888
	if (kvm_nlist (server->machine->kd, nlst2) < 0) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_nlist (cnt)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
#endif
Packit d37888
Packit d37888
	server->sysdeps.swap = _glibtop_sysdeps_swap;
Packit d37888
}
Packit d37888
Packit d37888
/* Provides information about swap usage. */
Packit d37888
Packit d37888
/*
Packit d37888
 * This function is based on a program called swapinfo written
Packit d37888
 * by Kevin Lahey <kml@rokkaku.atl.ga.us>.
Packit d37888
 */
Packit d37888
Packit d37888
void
Packit d37888
glibtop_get_swap_p (glibtop *server, glibtop_swap *buf)
Packit d37888
{
Packit d37888
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
Packit d37888
Packit d37888
# if (__FreeBSD__ < 4) && !defined(__FreeBSD_kernel__)
Packit d37888
	char *header;
Packit d37888
	int hlen, nswdev, dmmax;
Packit d37888
	int div, nfree, npfree;
Packit d37888
	struct swdevt *sw;
Packit d37888
	long blocksize, *perdev;
Packit d37888
	struct rlist head;
Packit d37888
	struct rlisthdr swaplist;
Packit d37888
	struct rlist *swapptr;
Packit d37888
	size_t sw_size;
Packit d37888
	u_long ptr;
Packit d37888
# else
Packit d37888
	int nswdev;
Packit d37888
	struct kvm_swap kvmsw[16];
Packit d37888
# endif
Packit d37888
Packit d37888
#elif defined(__bsdi__)
Packit d37888
	struct swapstats swap;
Packit d37888
#elif defined(__NetBSD__) || defined(__OpenBSD__)
Packit d37888
	struct swapent *swaplist;
Packit d37888
#endif
Packit d37888
Packit d37888
	int nswap, i;
Packit d37888
	guint64 avail = 0, inuse = 0;
Packit d37888
Packit d37888
#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) || defined(__OpenBSD__)
Packit d37888
	struct uvmexp uvmexp;
Packit d37888
	size_t length_uvmexp;
Packit d37888
#else
Packit d37888
	/* To get `pagein' and `pageout'. */
Packit d37888
	struct vmmeter vmm;
Packit d37888
#endif
Packit d37888
        static int swappgsin = -1;
Packit d37888
	static int swappgsout = -1;
Packit d37888
Packit d37888
	glibtop_init_p (server, (1L << GLIBTOP_SYSDEPS_SWAP), 0);
Packit d37888
Packit d37888
	memset (buf, 0, sizeof (glibtop_swap));
Packit d37888
Packit d37888
	if (server->sysdeps.swap == 0)
Packit d37888
		return;
Packit d37888
Packit d37888
#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) || defined(__OpenBSD__)
Packit d37888
	length_uvmexp = sizeof (uvmexp);
Packit d37888
	if (sysctl (mib_uvmexp, 2, &uvmexp, &length_uvmexp, NULL, 0)) {
Packit d37888
		glibtop_warn_io_r (server, "sysctl (uvmexp)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
#else
Packit d37888
	/* This is used to get the `pagein' and `pageout' members. */
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, nlst2[0].n_value,
Packit d37888
		      &vmm, sizeof (vmm)) != sizeof (vmm)) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (cnt)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
#endif
Packit d37888
Packit d37888
        if (swappgsin < 0) {
Packit d37888
		buf->pagein = 0;
Packit d37888
		buf->pageout = 0;
Packit d37888
	} else {
Packit d37888
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
Packit d37888
		buf->pagein = vmm.v_swappgsin - swappgsin;
Packit d37888
		buf->pageout = vmm.v_swappgsout - swappgsout;
Packit d37888
#elif defined(__NetBSD__) && (__NetBSD_Version__ >= 599002100)
Packit d37888
		/* no uvmexp.swap{ins,outs} */
Packit d37888
		buf->pagein = 0;
Packit d37888
		buf->pageout = 0;
Packit d37888
#elif defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) || defined(__OpenBSD__)
Packit d37888
		buf->pagein = uvmexp.swapins - swappgsin;
Packit d37888
		buf->pageout = uvmexp.swapouts - swappgsout;
Packit d37888
#else
Packit d37888
		buf->pagein = vmm.v_swpin - swappgsin;
Packit d37888
		buf->pageout = vmm.v_swpout - swappgsout;
Packit d37888
#endif
Packit d37888
	}
Packit d37888
Packit d37888
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
Packit d37888
        swappgsin = vmm.v_swappgsin;
Packit d37888
	swappgsout = vmm.v_swappgsout;
Packit d37888
#elif defined(__NetBSD__) && (__NetBSD_Version__ >= 599002100)
Packit d37888
	swappgsin = 0;
Packit d37888
	swappgsout = 0;
Packit d37888
#elif defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) || defined(__OpenBSD__)
Packit d37888
	swappgsin = uvmexp.swapins;
Packit d37888
	swappgsout = uvmexp.swapouts;
Packit d37888
#else
Packit d37888
	swappgsin = vmm.v_swpin;
Packit d37888
	swappgsout = vmm.v_swpout;
Packit d37888
#endif
Packit d37888
Packit d37888
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
Packit d37888
Packit d37888
#if (__FreeBSD__ < 4) && !defined(__FreeBSD_kernel__)
Packit d37888
Packit d37888
	/* Size of largest swap device. */
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, nlst[VM_NSWAP].n_value,
Packit d37888
		      &nswap, sizeof (nswap)) != sizeof (nswap)) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (nswap)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	/* Number of swap devices. */
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, nlst[VM_NSWDEV].n_value,
Packit d37888
		      &nswdev, sizeof (nswdev)) != sizeof (nswdev)) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (nswdev)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	/* Maximum size of a swap block. */
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, nlst[VM_DMMAX].n_value,
Packit d37888
		      &dmmax, sizeof (dmmax)) != sizeof (dmmax)) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (dmmax)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	/* List of free swap areas. */
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, nlst[VM_SWAPLIST].n_value,
Packit d37888
		      &swaplist, sizeof (swaplist)) != sizeof (swaplist)) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (swaplist)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	/* Kernel offset of list of swap devices and sizes. */
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, nlst[VM_SWDEVT].n_value,
Packit d37888
		      &ptr, sizeof (ptr)) != sizeof (ptr)) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (swdevt)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	/* List of swap devices and sizes. */
Packit d37888
Packit d37888
	sw_size = nswdev * sizeof (*sw);
Packit d37888
	sw = g_malloc (sw_size);
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, ptr, sw, sw_size) != (ssize_t)sw_size) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (*swdevt)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	perdev = g_malloc (nswdev * sizeof (*perdev));
Packit d37888
Packit d37888
	/* Count up swap space. */
Packit d37888
Packit d37888
	nfree = 0;
Packit d37888
	memset (perdev, 0, nswdev * sizeof(*perdev));
Packit d37888
Packit d37888
	swapptr = swaplist.rlh_list;
Packit d37888
Packit d37888
	while (swapptr) {
Packit d37888
		int	top, bottom, next_block;
Packit d37888
Packit d37888
		if (kvm_read (server->machine->kd, (int) swapptr, &head,
Packit d37888
			      sizeof (struct rlist)) != sizeof (struct rlist)) {
Packit d37888
			glibtop_warn_io_r (server, "kvm_read (swapptr)");
Packit d37888
			return;
Packit d37888
		}
Packit d37888
Packit d37888
		top = head.rl_end;
Packit d37888
		bottom = head.rl_start;
Packit d37888
Packit d37888
		nfree += top - bottom + 1;
Packit d37888
Packit d37888
		/*
Packit d37888
		 * Swap space is split up among the configured disks.
Packit d37888
		 *
Packit d37888
		 * For interleaved swap devices, the first dmmax blocks
Packit d37888
		 * of swap space some from the first disk, the next dmmax
Packit d37888
		 * blocks from the next, and so on up to nswap blocks.
Packit d37888
		 *
Packit d37888
		 * The list of free space joins adjacent free blocks,
Packit d37888
		 * ignoring device boundries.  If we want to keep track
Packit d37888
		 * of this information per device, we'll just have to
Packit d37888
		 * extract it ourselves.
Packit d37888
		 */
Packit d37888
		while (top / dmmax != bottom / dmmax) {
Packit d37888
			next_block = ((bottom + dmmax) / dmmax);
Packit d37888
			perdev[(bottom / dmmax) % nswdev] +=
Packit d37888
				next_block * dmmax - bottom;
Packit d37888
			bottom = next_block * dmmax;
Packit d37888
		}
Packit d37888
		perdev[(bottom / dmmax) % nswdev] +=
Packit d37888
			top - bottom + 1;
Packit d37888
Packit d37888
		swapptr = head.rl_next;
Packit d37888
	}
Packit d37888
Packit d37888
	header = getbsize (&hlen, &blocksize);
Packit d37888
Packit d37888
	div = blocksize / 512;
Packit d37888
	avail = npfree = 0;
Packit d37888
	for (i = 0; i < nswdev; i++) {
Packit d37888
		int xsize, xfree;
Packit d37888
Packit d37888
		/*
Packit d37888
		 * Don't report statistics for partitions which have not
Packit d37888
		 * yet been activated via swapon(8).
Packit d37888
		 */
Packit d37888
		if (!(sw[i].sw_flags & SW_FREED))
Packit d37888
			continue;
Packit d37888
Packit d37888
		/* The first dmmax is never allocated to avoid trashing of
Packit d37888
		 * disklabels
Packit d37888
		 */
Packit d37888
		xsize = sw[i].sw_nblks - dmmax;
Packit d37888
		xfree = perdev[i];
Packit d37888
		inuse = xsize - xfree;
Packit d37888
		npfree++;
Packit d37888
		avail += xsize;
Packit d37888
	}
Packit d37888
Packit d37888
	/*
Packit d37888
	 * If only one partition has been set up via swapon(8), we don't
Packit d37888
	 * need to bother with totals.
Packit d37888
	 */
Packit d37888
	inuse = avail - nfree;
Packit d37888
Packit d37888
	g_free (sw);
Packit d37888
	g_free (perdev);
Packit d37888
Packit d37888
	buf->flags = _glibtop_sysdeps_swap;
Packit d37888
Packit d37888
	buf->used = inuse;
Packit d37888
	buf->free = avail;
Packit d37888
Packit d37888
	buf->total = inuse + avail;
Packit d37888
Packit d37888
#else
Packit d37888
Packit d37888
	nswdev = kvm_getswapinfo(server->machine->kd, kvmsw, 16, 0);
Packit d37888
Packit d37888
	buf->flags = _glibtop_sysdeps_swap;
Packit d37888
Packit d37888
	buf->used = kvmsw[nswdev].ksw_used * getpagesize();
Packit d37888
	buf->total = kvmsw[nswdev].ksw_total * getpagesize();
Packit d37888
Packit d37888
	buf->free = buf->total - buf->used;
Packit d37888
Packit d37888
#endif
Packit d37888
Packit d37888
#elif defined(__bsdi__)
Packit d37888
Packit d37888
	/* General info about swap devices. */
Packit d37888
Packit d37888
	if (kvm_read (server->machine->kd, nlst[0].n_value,
Packit d37888
		      &swap, sizeof (swap)) != sizeof (swap)) {
Packit d37888
		glibtop_warn_io_r (server, "kvm_read (swap)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	buf->flags = _glibtop_sysdeps_swap;
Packit d37888
Packit d37888
	buf->used = swap.swap_total - swap.swap_free;
Packit d37888
	buf->free = swap.swap_free;
Packit d37888
Packit d37888
	buf->total = swap.swap_total;
Packit d37888
Packit d37888
#elif defined(__NetBSD__) || defined(__OpenBSD__)
Packit d37888
Packit d37888
	nswap = swapctl (SWAP_NSWAP, NULL, 0);
Packit d37888
	if (nswap < 0) {
Packit d37888
		glibtop_warn_io_r (server, "swapctl (SWAP_NSWAP)");
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	swaplist = g_malloc (nswap * sizeof (struct swapent));
Packit d37888
Packit d37888
	if (swapctl (SWAP_STATS, swaplist, nswap) != nswap) {
Packit d37888
		glibtop_warn_io_r (server, "swapctl (SWAP_STATS)");
Packit d37888
		g_free (swaplist);
Packit d37888
		return;
Packit d37888
	}
Packit d37888
Packit d37888
	for (i = 0; i < nswap; i++) {
Packit d37888
		avail += swaplist[i].se_nblks;
Packit d37888
		inuse += swaplist[i].se_inuse;
Packit d37888
	}
Packit d37888
Packit d37888
	g_free (swaplist);
Packit d37888
Packit d37888
	buf->flags = _glibtop_sysdeps_swap;
Packit d37888
Packit d37888
	buf->used = inuse;
Packit d37888
	buf->free = avail;
Packit d37888
Packit d37888
	buf->total = inuse + avail;
Packit d37888
#endif
Packit d37888
}