Blame sysdeps/bsd/swap.c

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