diff --git a/sysdeps/freebsd/ChangeLog b/sysdeps/freebsd/ChangeLog index 21372d18..4f14117e 100644 --- a/sysdeps/freebsd/ChangeLog +++ b/sysdeps/freebsd/ChangeLog @@ -1,3 +1,8 @@ +1998-08-08 Martin Baulig + + * swap.c: Added swap usage based upton the source code + of `pinfo'. + 1998-08-07 Martin Baulig * *: Imported FreeBSD port of libgtop from Josh Sled. diff --git a/sysdeps/freebsd/swap.c b/sysdeps/freebsd/swap.c index e0f72cae..c2b5c406 100644 --- a/sysdeps/freebsd/swap.c +++ b/sysdeps/freebsd/swap.c @@ -23,16 +23,39 @@ #include #include +#include + #include +#include +#include + static const unsigned long _glibtop_sysdeps_swap = 0; +/* nlist structure for kernel access */ +static struct nlist nlst [] = { +#define VM_SWAPLIST 0 + { "_swaplist" },/* list of free swap areas */ +#define VM_SWDEVT 1 + { "_swdevt" }, /* list of swap devices and sizes */ +#define VM_NSWAP 2 + { "_nswap" }, /* size of largest swap device */ +#define VM_NSWDEV 3 + { "_nswdev" }, /* number of swap devices */ +#define VM_DMMAX 4 + { "_dmmax" }, /* maximum size of a swap block */ + { 0 } +}; + /* Init function. */ void glibtop_init_swap_p (glibtop *server) { server->sysdeps.swap = _glibtop_sysdeps_swap; + + if (kvm_nlist (server->machine.kd, nlst) != 0) + glibtop_error_io_r (server, "kvm_nlist"); } /* Provides information about swap usage. */ @@ -40,7 +63,140 @@ glibtop_init_swap_p (glibtop *server) void glibtop_get_swap_p (glibtop *server, glibtop_swap *buf) { + char *header; + int hlen, nswap, nswdev, dmmax; + int i, div, avail, nfree, npfree, used; + struct swdevt *sw; + long blocksize, *perdev; + struct rlist head; + struct rlisthdr swaplist; + struct rlist *swapptr; + size_t sw_size; + u_long ptr; + glibtop_init_p (server, GLIBTOP_SYSDEPS_SWAP, 0); memset (buf, 0, sizeof (glibtop_swap)); + + /* Size of largest swap device. */ + + if (kvm_read (server->machine.kd, nlst[VM_NSWAP].n_value, + &nswap, sizeof (nswap)) != sizeof (nswap)) + glibtop_error_io_r (server, "kvm_read (nswap)"); + + /* Number of swap devices. */ + + if (kvm_read (server->machine.kd, nlst[VM_NSWDEV].n_value, + &nswdev, sizeof (nswdev)) != sizeof (nswdev)) + glibtop_error_io_r (server, "kvm_read (nswdev)"); + + /* Maximum size of a swap block. */ + + if (kvm_read (server->machine.kd, nlst[VM_DMMAX].n_value, + &dmmax, sizeof (dmmax)) != sizeof (dmmax)) + glibtop_error_io_r (server, "kvm_read (dmmax)"); + + /* List of free swap areas. */ + + if (kvm_read (server->machine.kd, nlst[VM_SWAPLIST].n_value, + &swaplist, sizeof (swaplist)) != sizeof (swaplist)) + glibtop_error_io_r (server, "kvm_read (swaplist)"); + + /* Kernel offset of list of swap devices and sizes. */ + + if (kvm_read (server->machine.kd, nlst[VM_SWDEVT].n_value, + &ptr, sizeof (ptr)) != sizeof (ptr)) + glibtop_error_io_r (server, "kvm_read (swaplist)"); + + /* List of swap devices and sizes. */ + + sw_size = nswdev * sizeof (*sw); + sw = glibtop_malloc_r (server, sw_size); + + if (kvm_read (server->machine.kd, ptr, sw, sw_size) != sw_size) + glibtop_error_io_r (server, "kvm_read (*swdevt)"); + + perdev = glibtop_malloc (nswdev * sizeof (*perdev)); + + /* Count up swap space. */ + + nfree = 0; + memset (perdev, 0, nswdev * sizeof(*perdev)); + + swapptr = swaplist.rlh_list; + + while (swapptr) { + int top, bottom, next_block; + + if (kvm_read (server->machine.kd, swapptr, &head, + sizeof (struct rlist)) != sizeof (struct rlist)) + glibtop_error_io_r (server, "kvm_read (swapptr)"); + + top = head.rl_end; + bottom = head.rl_start; + + nfree += top - bottom + 1; + + /* + * Swap space is split up among the configured disks. + * + * For interleaved swap devices, the first dmmax blocks + * of swap space some from the first disk, the next dmmax + * blocks from the next, and so on up to nswap blocks. + * + * 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); + perdev[(bottom / dmmax) % nswdev] += + next_block * dmmax - bottom; + bottom = next_block * dmmax; + } + perdev[(bottom / dmmax) % nswdev] += + top - bottom + 1; + + swapptr = head.rl_next; + } + + header = getbsize (&hlen, &blocksize); + + div = blocksize / 512; + avail = npfree = 0; + for (i = 0; i < nswdev; i++) { + int xsize, xfree; + + /* + * Don't report statistics for partitions which have not + * yet been activated via swapon(8). + */ + if (!(sw[i].sw_flags & SW_FREED)) + continue; + + /* The first dmmax is never allocated to avoid trashing of + * disklabels + */ + xsize = sw[i].sw_nblks - dmmax; + xfree = perdev[i]; + used = xsize - xfree; + npfree++; + avail += xsize; + } + + /* + * If only one partition has been set up via swapon(8), we don't + * need to bother with totals. + */ + used = avail - nfree; + + glibtop_free_r (server, sw); + glibtop_free_r (server, perdev); + + buf->used = used; + buf->free = avail; + + buf->total = used + avail; + buf->flags = _glibtop_sysdeps_swap; }