kvm_getswapinfo.c revision 43048
154331Sarchie/* 254331Sarchie * Copyright (c) 1999, Matthew Dillon. All Rights Reserved. 354331Sarchie * 454331Sarchie * Redistribution and use in source and binary forms, with or without 554331Sarchie * modification, are permitted provided under the terms of the BSD 654331Sarchie * Copyright as found in /usr/src/COPYRIGHT in the FreeBSD source tree. 754331Sarchie */ 854331Sarchie 954331Sarchie#ifndef lint 1054331Sarchiestatic const char copyright[] = 1154331Sarchie "@(#) Copyright (c) 1999\n" 1254331Sarchie "Matthew Dillon. All rights reserved.\n"; 1354331Sarchie#endif /* not lint */ 1454331Sarchie 1554331Sarchie#ifndef lint 1654331Sarchiestatic const char rcsid[] = 1754331Sarchie "$Id: kvm_getswapinfo.c,v 1.1 1999/01/22 10:36:04 dillon Exp $"; 1854331Sarchie#endif /* not lint */ 1954331Sarchie 2054331Sarchie#include <sys/param.h> 2154331Sarchie#include <sys/time.h> 2254331Sarchie#include <sys/vnode.h> 2354331Sarchie#include <sys/ucred.h> 2454331Sarchie#include <sys/stat.h> 2554331Sarchie#include <sys/conf.h> 2654331Sarchie#include <sys/rlist.h> 2754331Sarchie#include <sys/blist.h> 2854331Sarchie 2954331Sarchie#include <err.h> 3054331Sarchie#include <fcntl.h> 3154331Sarchie#include <kvm.h> 3254331Sarchie#include <limits.h> 3354331Sarchie#include <nlist.h> 3454331Sarchie#include <stdio.h> 3554331Sarchie#include <stdlib.h> 3654331Sarchie#include <string.h> 3754331Sarchie#include <unistd.h> 3854331Sarchie 3954331Sarchiestatic struct nlist kvm_swap_nl[] = { 4054331Sarchie { "_swaplist" }, /* old style swap list */ 4154331Sarchie { "_swapblist" }, /* new radix swap list */ 4254331Sarchie { "_swdevt" }, /* list of swap devices and sizes */ 4354331Sarchie { "_nswdev" }, /* number of swap devices */ 4454331Sarchie { "_dmmax" }, /* maximum size of a swap block */ 4554331Sarchie { "" } 4654331Sarchie}; 4754331Sarchie 4854331Sarchie#define NL_SWAPLIST 0 4954331Sarchie#define NL_SWAPBLIST 1 5054331Sarchie#define NL_SWDEVT 2 5154331Sarchie#define NL_NSWDEV 3 5254331Sarchie#define NL_DMMAX 4 5354331Sarchie 5454331Sarchiestatic int kvm_swap_nl_cached = 0; 5554331Sarchiestatic int nswdev; 5654331Sarchiestatic int unswdev; 5754331Sarchiestatic int dmmax; 5854331Sarchiestatic int type; 5954331Sarchie 6054331Sarchiestatic void getswapinfo_old(kvm_t *kd, kvm_swap_t swap_ary, int swap_max, int flags); 6154331Sarchiestatic void getswapinfo_radix(kvm_t *kd, kvm_swap_t swap_ary, int swap_max, int flags); 6254331Sarchie 6354331Sarchie#define SVAR(var) __STRING(var) /* to force expansion */ 6454331Sarchie#define KGET(idx, var) \ 6554331Sarchie KGET1(idx, &var, sizeof(var), SVAR(var)) 6654331Sarchie#define KGET1(idx, p, s, msg) \ 6754331Sarchie KGET2(kvm_swap_nl[idx].n_value, p, s, msg) 6854331Sarchie#define KGET2(addr, p, s, msg) \ 6954331Sarchie if (kvm_read(kd, (u_long)(addr), p, s) != s) \ 7054331Sarchie warnx("cannot read %s: %s", msg, kvm_geterr(kd)) 7154331Sarchie#define KGETN(idx, var) \ 7254331Sarchie KGET1N(idx, &var, sizeof(var), SVAR(var)) 7354331Sarchie#define KGET1N(idx, p, s, msg) \ 7454331Sarchie KGET2N(kvm_swap_nl[idx].n_value, p, s, msg) 7554331Sarchie#define KGET2N(addr, p, s, msg) \ 7654331Sarchie ((kvm_read(kd, (u_long)(addr), p, s) == s) ? 1 : 0) 7754331Sarchie#define KGETRET(addr, p, s, msg) \ 7854331Sarchie if (kvm_read(kd, (u_long)(addr), p, s) != s) { \ 7954331Sarchie warnx("cannot read %s: %s", msg, kvm_geterr(kd)); \ 8054331Sarchie return (0); \ 8154331Sarchie } 8254331Sarchie 8354331Sarchieint 8454331Sarchiekvm_getswapinfo( 8554331Sarchie kvm_t *kd, 8654331Sarchie struct kvm_swap *swap_ary, 8754331Sarchie int swap_max, 8854331Sarchie int flags 8954331Sarchie) { 9054331Sarchie int ti = 0; 9154331Sarchie 9254331Sarchie /* 9354331Sarchie * clear cache 9454331Sarchie */ 9554331Sarchie if (kd == NULL) { 9654331Sarchie kvm_swap_nl_cached = 0; 9754331Sarchie return(0); 9854331Sarchie } 9954331Sarchie 10054331Sarchie /* 10154331Sarchie * namelist 10254331Sarchie */ 10354331Sarchie if (kvm_swap_nl_cached == 0) { 10454331Sarchie struct swdevt *sw; 10554331Sarchie 10654331Sarchie if (kvm_nlist(kd, kvm_swap_nl) < 0) 10754331Sarchie return(-1); 10854331Sarchie 10954331Sarchie /* 11054331Sarchie * required entries 11154331Sarchie */ 11254331Sarchie 11354331Sarchie if ( 11454331Sarchie kvm_swap_nl[NL_SWDEVT].n_value == 0 || 11554331Sarchie kvm_swap_nl[NL_NSWDEV].n_value == 0 || 11654331Sarchie kvm_swap_nl[NL_DMMAX].n_value == 0 11754331Sarchie ) { 11854331Sarchie return(-1); 11954331Sarchie } 12054331Sarchie 12154331Sarchie /* 12254331Sarchie * get globals, type of swap 12354331Sarchie */ 12454331Sarchie 12554331Sarchie KGET(NL_NSWDEV, nswdev); 12654331Sarchie KGET(NL_DMMAX, dmmax); 12754331Sarchie 12854331Sarchie if (kvm_swap_nl[NL_SWAPLIST].n_value) 12954331Sarchie type = 1; 13054331Sarchie 13160009Sarchie if (kvm_swap_nl[NL_SWAPBLIST].n_value) 13260009Sarchie type = 2; 13354331Sarchie 13454331Sarchie /* 13554331Sarchie * figure out how many actual swap devices are enabled 13654331Sarchie */ 13754331Sarchie 13854331Sarchie KGET(NL_SWDEVT, sw); 13954331Sarchie for (unswdev = nswdev - 1; unswdev >= 0; --unswdev) { 14054331Sarchie struct swdevt swinfo; 14162129Sarchie 14262129Sarchie KGET2(&sw[unswdev], &swinfo, sizeof(swinfo), "swinfo"); 14362129Sarchie if (swinfo.sw_nblks) 14454331Sarchie break; 14554331Sarchie } 14654331Sarchie ++unswdev; 14754331Sarchie 14854331Sarchie kvm_swap_nl_cached = 1; 14954331Sarchie } 15054331Sarchie 15154331Sarchie 15254331Sarchie { 15354331Sarchie struct swdevt *sw; 15454331Sarchie int i; 15554331Sarchie 15654331Sarchie ti = unswdev; 15754331Sarchie if (ti >= swap_max) 15854331Sarchie ti = swap_max - 1; 15954331Sarchie 16054331Sarchie if (ti >= 0) 16154331Sarchie bzero(swap_ary, sizeof(struct kvm_swap) * (ti + 1)); 16254331Sarchie 16360009Sarchie KGET(NL_SWDEVT, sw); 16454331Sarchie for (i = 0; i < unswdev; ++i) { 16554331Sarchie struct swdevt swinfo; 16654331Sarchie int ttl; 16754331Sarchie 16854331Sarchie KGET2(&sw[i], &swinfo, sizeof(swinfo), "swinfo"); 16954331Sarchie 17054331Sarchie /* 17154331Sarchie * old style: everything in DEV_BSIZE'd chunks, 17254331Sarchie * convert to pages. 17354331Sarchie * 17454331Sarchie * new style: swinfo in DEV_BSIZE'd chunks but dmmax 17554331Sarchie * in pages. 17654331Sarchie */ 17754331Sarchie 17860009Sarchie if (type == 1) 17954331Sarchie ttl = dbtoc(swinfo.sw_nblks); 18054331Sarchie else 18154331Sarchie ttl = swinfo.sw_nblks; 18254331Sarchie 18354331Sarchie if (ttl == 0) 18454331Sarchie continue; 18554331Sarchie 18654331Sarchie if (i < ti) { 18754331Sarchie swap_ary[i].ksw_total = ttl; 18854331Sarchie swap_ary[i].ksw_used = ttl; 18954331Sarchie swap_ary[i].ksw_flags = swinfo.sw_flags; 19054331Sarchie if (swinfo.sw_dev == NODEV) { 19154331Sarchie snprintf( 19254331Sarchie swap_ary[i].ksw_devname, 19360009Sarchie sizeof(swap_ary[i].ksw_devname), 19460009Sarchie "%s", 19560009Sarchie "[NFS swap]" 19660009Sarchie ); 19760009Sarchie } else { 19860009Sarchie snprintf( 19960009Sarchie swap_ary[i].ksw_devname, 20060009Sarchie sizeof(swap_ary[i].ksw_devname), 20154331Sarchie "%s%s", 20254331Sarchie ((flags & SWIF_DEV_PREFIX) ? "/dev/" : ""), 20354331Sarchie devname(swinfo.sw_dev, S_IFBLK) 20454331Sarchie ); 20554331Sarchie } 20654331Sarchie } 20754331Sarchie if (ti >= 0) { 20854331Sarchie swap_ary[ti].ksw_total += ttl; 20954331Sarchie swap_ary[ti].ksw_used += ttl; 21054331Sarchie } 21154331Sarchie } 21254331Sarchie } 21354331Sarchie 21454331Sarchie switch(type) { 21554331Sarchie case 1: 21654331Sarchie getswapinfo_old(kd, swap_ary, swap_max, flags); 21760009Sarchie break; 21860009Sarchie case 2: 21960009Sarchie getswapinfo_radix(kd, swap_ary, swap_max, flags); 22060009Sarchie break; 22160009Sarchie default: 22260009Sarchie ti = -1; 22360009Sarchie break; 22460009Sarchie } 22560009Sarchie return(ti); 22660009Sarchie} 22760009Sarchie 22860009Sarchie/* 22960009Sarchie * scanradix() - support routine for radix scanner 23060009Sarchie */ 23160009Sarchie 23260009Sarchie#define TABME tab, tab, "" 23360009Sarchie 23460009Sarchiestatic int 23560009Sarchiescanradix( 23660009Sarchie blmeta_t *scan, 23760009Sarchie daddr_t blk, 23854331Sarchie daddr_t radix, 23954331Sarchie daddr_t skip, 24054331Sarchie daddr_t count, 24154331Sarchie kvm_t *kd, 24254331Sarchie int dmmax, 24354331Sarchie int nswdev, 24454331Sarchie kvm_swap_t swap_ary, 24554331Sarchie int swap_max, 24654331Sarchie int tab, 24754331Sarchie int flags 24854331Sarchie) { 24954331Sarchie blmeta_t meta; 25054331Sarchie int ti = (unswdev >= swap_max) ? swap_max - 1 : unswdev; 25154331Sarchie 25254331Sarchie KGET2(scan, &meta, sizeof(meta), "blmeta_t"); 25354331Sarchie 25454331Sarchie /* 25554331Sarchie * Terminator 25654331Sarchie */ 25754331Sarchie if (meta.bm_bighint == (daddr_t)-1) { 25854331Sarchie if (flags & SWIF_DUMP_TREE) { 25954331Sarchie printf("%*.*s(0x%06x,%d) Terminator\n", 26054331Sarchie TABME, 26154331Sarchie blk, 26254331Sarchie radix 26354331Sarchie ); 26454331Sarchie } 26554331Sarchie return(-1); 26654331Sarchie } 26754331Sarchie 26854331Sarchie if (radix == BLIST_BMAP_RADIX) { 26954331Sarchie /* 27054331Sarchie * Leaf bitmap 27154331Sarchie */ 27254331Sarchie int i; 27354331Sarchie 27454331Sarchie if (flags & SWIF_DUMP_TREE) { 27554331Sarchie printf("%*.*s(0x%06x,%d) Bitmap %08x big=%d\n", 27654331Sarchie TABME, 27754331Sarchie blk, 27854331Sarchie radix, 27954331Sarchie (int)meta.u.bmu_bitmap, 28054331Sarchie meta.bm_bighint 28154331Sarchie ); 28254331Sarchie } 28354331Sarchie 28454331Sarchie /* 28554331Sarchie * If not all allocated, count. 28654331Sarchie */ 28754331Sarchie if (meta.u.bmu_bitmap != 0) { 28854331Sarchie for (i = 0; i < BLIST_BMAP_RADIX && i < count; ++i) { 28954331Sarchie /* 29054331Sarchie * A 0 bit means allocated 29154331Sarchie */ 29254331Sarchie if ((meta.u.bmu_bitmap & (1 << i))) { 29354331Sarchie int t = 0; 29454331Sarchie 29554331Sarchie if (nswdev) 29654331Sarchie t = (blk + i) / dmmax % nswdev; 29754331Sarchie if (t < ti) 29854331Sarchie --swap_ary[t].ksw_used; 29954331Sarchie if (ti >= 0) 30054331Sarchie --swap_ary[ti].ksw_used; 30154331Sarchie } 30254331Sarchie } 30354331Sarchie } 30454331Sarchie } else if (meta.u.bmu_avail == radix) { 30554331Sarchie /* 30654331Sarchie * Meta node if all free 30754331Sarchie */ 30854331Sarchie if (flags & SWIF_DUMP_TREE) { 30954331Sarchie printf("%*.*s(0x%06x,%d) Submap ALL-FREE {\n", 31054331Sarchie TABME, 31154331Sarchie blk, 31254331Sarchie radix, 31354331Sarchie (int)meta.u.bmu_avail, 31454331Sarchie meta.bm_bighint 31554331Sarchie ); 31654331Sarchie } 31754331Sarchie /* 31854331Sarchie * Note: both dmmax and radix are powers of 2. However, dmmax 31954331Sarchie * may be larger then radix so use a smaller increment if 32054331Sarchie * necessary. 32154331Sarchie */ 32254331Sarchie { 32354331Sarchie int t; 32454331Sarchie int tinc = dmmax; 32554331Sarchie 32659728Sjulian while (tinc > radix) 32754331Sarchie tinc >>= 1; 32854331Sarchie 32954331Sarchie for (t = blk; t < blk + radix; t += tinc) { 33054331Sarchie int u = (nswdev) ? (t / dmmax % nswdev) : 0; 33154331Sarchie 33254331Sarchie if (u < ti) 33354331Sarchie swap_ary[u].ksw_used -= tinc; 33454331Sarchie if (ti >= 0) 33554331Sarchie swap_ary[ti].ksw_used -= tinc; 33654331Sarchie } 33754331Sarchie } 33854331Sarchie } else if (meta.u.bmu_avail == 0) { 33954331Sarchie /* 34054331Sarchie * Meta node if all used 34154331Sarchie */ 34254331Sarchie if (flags & SWIF_DUMP_TREE) { 34354331Sarchie printf("%*.*s(0x%06x,%d) Submap ALL-ALLOCATED\n", 34454331Sarchie TABME, 34554331Sarchie blk, 34654331Sarchie radix, 34754331Sarchie (int)meta.u.bmu_avail, 34854331Sarchie meta.bm_bighint 34954331Sarchie ); 35054331Sarchie } 35154331Sarchie } else { 35254331Sarchie /* 35360009Sarchie * Meta node if not all free 35460009Sarchie */ 35560009Sarchie int i; 35660009Sarchie int next_skip; 35760009Sarchie 35860009Sarchie radix >>= BLIST_META_RADIX_SHIFT; 35960009Sarchie next_skip = skip >> BLIST_META_RADIX_SHIFT; 36060009Sarchie 36160009Sarchie if (flags & SWIF_DUMP_TREE) { 36260009Sarchie printf("%*.*s(0x%06x,%d) Submap avail=%d big=%d {\n", 36360009Sarchie TABME, 36460009Sarchie blk, 36560009Sarchie radix, 36660009Sarchie (int)meta.u.bmu_avail, 36760009Sarchie meta.bm_bighint 36860009Sarchie ); 36954331Sarchie } 37054331Sarchie 37154331Sarchie for (i = 1; i <= skip; i += next_skip) { 37254331Sarchie int r; 37354331Sarchie daddr_t vcount = (count > radix) ? radix : count; 37454331Sarchie 37554331Sarchie r = scanradix( 37654331Sarchie &scan[i], 37754331Sarchie blk, 37854331Sarchie radix, 37954331Sarchie next_skip - 1, 38054331Sarchie vcount, 38154331Sarchie kd, 38254331Sarchie dmmax, 38354331Sarchie nswdev, 38454331Sarchie swap_ary, 38554331Sarchie swap_max, 38654331Sarchie tab + 4, 38754331Sarchie flags 38854331Sarchie ); 38954331Sarchie if (r < 0) 39054331Sarchie break; 39154331Sarchie blk += radix; 39259728Sjulian } 39359728Sjulian if (flags & SWIF_DUMP_TREE) { 39454331Sarchie printf("%*.*s}\n", TABME); 39554331Sarchie } 39654331Sarchie } 39754331Sarchie return(0); 39854331Sarchie} 39954331Sarchie 40054331Sarchiestatic void 40154331Sarchiegetswapinfo_radix(kvm_t *kd, kvm_swap_t swap_ary, int swap_max, int flags) 40254331Sarchie{ 40354331Sarchie struct blist *swapblist = NULL; 40454331Sarchie struct blist blcopy = { 0 }; 40554331Sarchie 40654331Sarchie KGET(NL_SWAPBLIST, swapblist); 40754331Sarchie KGET2(swapblist, &blcopy, sizeof(blcopy), "*swapblist"); 40854331Sarchie 40954331Sarchie if (flags & SWIF_DUMP_TREE) { 41054331Sarchie printf("radix tree: %d/%d/%d blocks, %dK wired\n", 41154331Sarchie blcopy.bl_free, 41254331Sarchie blcopy.bl_blocks, 41354331Sarchie blcopy.bl_radix, 41454331Sarchie (blcopy.bl_rootblks * sizeof(blmeta_t) + 1023)/ 41554331Sarchie 1024 41654331Sarchie ); 41754331Sarchie } 41854331Sarchie scanradix( 41954331Sarchie blcopy.bl_root, 42062129Sarchie 0, 42154331Sarchie blcopy.bl_radix, 42254331Sarchie blcopy.bl_skip, 42354331Sarchie blcopy.bl_rootblks, 42454331Sarchie kd, 42554331Sarchie dmmax, 42654331Sarchie nswdev, 42754331Sarchie swap_ary, 42854331Sarchie swap_max, 42954331Sarchie 0, 43054331Sarchie flags 43154331Sarchie ); 43254331Sarchie} 43354331Sarchie 43454331Sarchiestatic void 43554331Sarchiegetswapinfo_old(kvm_t *kd, kvm_swap_t swap_ary, int swap_max, int flags) 43654331Sarchie{ 43754331Sarchie struct rlist *swapptr; 43854331Sarchie struct rlisthdr swaplist; 43954331Sarchie int ti = (unswdev >= swap_max) ? swap_max - 1 : unswdev; 44054331Sarchie 44154331Sarchie KGET(NL_SWAPLIST, swaplist); 44254331Sarchie 44354331Sarchie swapptr = swaplist.rlh_list; 44454331Sarchie 44554331Sarchie while (swapptr) { 44654331Sarchie int top; 44754331Sarchie int bottom; 44854331Sarchie int next_block; 44954331Sarchie int t; 45054331Sarchie int v; 45154331Sarchie struct rlist head; 45254331Sarchie 45354331Sarchie KGET2(swapptr, &head, sizeof(head), "swapptr"); 45454331Sarchie 45554331Sarchie top = head.rl_end; 45654331Sarchie bottom = head.rl_start; 45754331Sarchie 45854331Sarchie /* 45954331Sarchie * Handle interleave indexing 46054331Sarchie */ 46154331Sarchie 46254331Sarchie while (top / dmmax != bottom / dmmax) { 46354331Sarchie next_block = ((bottom + dmmax) / dmmax); 46454331Sarchie 46554331Sarchie t = (bottom / dmmax) % nswdev; 46654331Sarchie v = next_block * dmmax - bottom; 46754331Sarchie 46854331Sarchie if (t < ti) 46954331Sarchie swap_ary[t].ksw_used -= dbtoc(v); 47054331Sarchie if (ti >= 0) 47154331Sarchie swap_ary[ti].ksw_used -= dbtoc(v); 47254331Sarchie 47360009Sarchie bottom = next_block * dmmax; 47460009Sarchie } 47554331Sarchie 47660009Sarchie t = (bottom / dmmax) % nswdev; 47760009Sarchie v = top - bottom + 1; 47860009Sarchie 47960009Sarchie if (t < ti) 48060009Sarchie swap_ary[t].ksw_used -= dbtoc(v); 48160009Sarchie if (ti >= 0) 48260009Sarchie swap_ary[ti].ksw_used -= dbtoc(v); 48354331Sarchie 48460009Sarchie swapptr = head.rl_next; 48560009Sarchie } 48660009Sarchie} 48760009Sarchie 48860009Sarchie